第11章字符串和字符串函数
编程练习
1.设计并测试一个函数,可以从输入读取n个字符(包括空格、制表符和换行符),把结果存储在一个数组中,这个数组的地址通过参数来传递。
#include
void input(char *p, int n);
int main(void)
{
char a[81];
int n;
puts("input the char number of your string:");
scanf("%d",&n);
getchar(); //滤去回车
puts("input your string:");
input(a,n);
puts(a);
return 0;
}
void input(char *p, int n)
{
int i;
for (i=0;i *(p+i) = getchar(); *(p+i) = '\0'; } 2.修改并测试练习1中的函数,使得可以在n个字符后,或第一个空格、制表符、换行符后停止读取输入,由上述情况中最先被满足的那个终止读取(不能用scanf()函数)。 #include #include void input(char *p, int n); int main(void) { char a[81]; int n; puts("input the char number of your string:"); scanf("%d",&n); getchar(); //滤去回车 puts("input your string:"); input(a,n); puts(a); return 0; } void input(char *p, int n) { int i; for (i=0;i { *(p+i) = getchar(); if( isspace(*(p+i)) ) break; } *(p+i) = '\0'; } 3.设计并测试一个函数,其功能是读取输入行里的第一个单词到数组,并丢掉该行中其他的字符。一个单词的定义是一串字符,其中不含空格、制表符和换行符。 #include #include void word(char *p); int main(void) { char a[81]; puts("input your string:"); gets(a); word(a); puts(a); return 0; } void word(char *p) { int begin,end; for(begin=0; isspace( *(p+begin) ) ;begin++) continue; for(end=begin; !isspace( *(p+end) ) ;end++) continue; *(p+end) = '\0'; for(; *(p + begin) != '\0'; p++) *p = *(p + begin); *p = '\0'; } 4.设计并测试一个函数,其功能是搜索由函数的第一个参数指定的字符串,在其中查找由函数的第二个参数指定的字符的第一次出现的位置。如果找到,返回指向这个字符的指针:如果没有找到,返回空字符(这种方式和strchr()函数的功能一样)。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。 #include char *mystrchr(char *, char ); int main(void) { char str[81]; char ch; char *p; do { puts("input range string:"); gets(str); puts("input match char:"); ch = getchar(); getchar(); p = mystrchr(str, ch); if ( p ) { puts("Find!"); puts(p); } else puts("Can't find!"); puts("input any char except q to go on."); gets(str); } while(*str != 'q'); puts("Quit."); return 0; } char *mystrchr(char *p, char ch) { char *p_save = p; if(*p == '\0') return NULL; while(1) { if(*p == ch) { return p_save; } else { if(*++p == '\0') return NULL; p_save = p; } } } 5.编写一个函数is_witlun()。它接受两个参数,一个是字符,另一个是字符串指针。其功能是如果字符在字符串中,就返回一个非O值(真);如果字符不在字符串中,就返回O值(假)。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。 #include int is_within(char *p, char ch); int main(void) { char str[81]; char ch; do { puts("input range string:"); gets(str); puts("input match char:"); ch = getchar(); getchar(); if ( is_within(str, ch) ) puts("Find!"); else puts("Can't find!"); puts("input any char except q to go on."); ch = getchar(); getchar(); } while(ch != 'q'); puts("Quit."); return 0; } int is_within(char *p, char ch) { while(*p != '\0') { if(*p == ch) return 1; p++; } return 0; } 6.strncpy (sl,s2,n)函数从s2复制n个字符给sl,并在必要时截断s2或为其填充额外的空字符。如果s2的长度等于或大于n,目标字符串就没有标志结束的空字符。函数返回sl。自己编写这个函数,并在一个使用循环语句为这个函数提供输入的完整程序中进行测试。 #include char *mystrncpy(char *p1, char *p2, int n); int main(void) { char str1[81]; char str2[81]; int n; do { puts("input string1:"); gets(str1); puts("input string2:"); gets(str2); puts("input the number of copying char:"); scanf("%d",&n); getchar(); puts("After copying:"); puts(mystrncpy(str1, str2, n)); puts("input any char except q to go on."); gets(str1); } while(*str1 != 'q'); puts("Quit."); return 0; } char *mystrncpy(char *p1, char *p2, int n) { char *p=p1; while(*p1++ != '\0') continue; *--p1 = *p2; n--; while(n>0 && *p2 != '\0') { *++p1 = *++p2; n--; } return p; } 7.编写一个函数string_in(),它接受两个字符串指针参数。如果第二个字符串被包含在第一个字符串中,函数就返回被包含的字符开始的地址。例如,string_in("hats","at")返回hats中a的地址,则,函数返回空指针。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。 #include char *string_in(char *p1, char *p2); int main(void) { char str1[81]; char str2[21]; char *p; do { puts("input range string:"); gets(str1); puts("input match string:"); gets(str2); p = string_in(str1, str2); if ( p ) { puts("Find!"); puts(p); } else puts("Can't find!"); puts("input any char except q to go on."); gets(str1); } while(*str1 != 'q'); puts("Quit."); return 0; } char *string_in(char *p1, char *p2) { char *p1_save = p1, *p2_save = p2; if(*p1 == '\0' || *p2 == '\0') return NULL; while(1) { if(*p1 == *p2) { if(*++p2 == '\0') return p1_save; if(*++p1 == '\0') return NULL; } else { if(*++p1 == '\0') return NULL; p1_save = p1; p2 = p2_save; } } } 8.编写一个函数,其功能是使输入字符串反序。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。 #include void reverse(char *p); int main(void) { char str[81]; do { puts("input a string:"); gets(str); reverse(str); puts(str); puts("input any char except q to go on."); gets(str); } while(*str != 'q'); puts("Quit."); return 0; } void reverse(char *p) { int i,n; char temp; for(n=0; *(p+n) != '\0'; n++) continue; n--; for(i=0; i < n-i; i++) { temp = p[i]; p[i] = p[n-i]; p[n-i] = temp; } } 9.编写一个函数。其参数为一个字符串,函数删除字符串中的空格。在一个可以循环读取的程序中进行测试,直到用户输入空行。对于任何输入字符串,函数都应该适用并可以显示结果。 #include void delspace(char *p1); int main(void) { char str[81]; do { puts("input a string:"); gets(str); delspace(str); puts(str); puts("input any char except q to go on."); gets(str); } while(*str != 'q'); puts("Quit."); return 0; } void delspace(char *p1) { char *p2; while (*p1 != '\0' ) { if (*p1 == ' ') { p2 = p1; while(*p2 != '\0') { *p2 = *(p2+1); p2++; } p1--; //抵消下面的p1++ } p1++; } } 10.编写一个程序,读取输入,直到读入了10个字符串或遇到EOF,由二者中最先被满足的那个终止读取过程。这个程序可以为用户提供一个有5个选项的菜单:输出初始字符串列表、按ASCII顺序输出字符串、按长度递增顺序输出字符串、按字符串中第一个单词的长度输出字符串和退出。菜单可以循环,直到用户输入退出请求。当然,程序要能真正完成菜单中的各项功能。 #include #include #include void origin_put(char **p, int n); void ascii_put(char **p, int n); void length_put(char **p, int n); int first_word_length(char *p); int first_word_length(char *p); void word_put(char **p, int n); int main(void) { char str[10][81]; char *p[10]; char command[10]; int n; while(1) { n = 0; puts("input no more than 10 strings finished by EOF (^Z):"); do { if ( gets(str[n]) == NULL ) break; p[n] = str[n]; n++; } while( n<10 ); puts("select:"); puts("a. put originally"); puts("b. put in order of ascii"); puts("c. put in order of string's length"); puts("d. put in order of first word's length"); puts("e. input strings again"); puts("q. quit"); do { gets(command); switch(command[0]) { case 'a': puts("put originally:"); origin_put(p,n); break; case 'b': puts("put in order of ascii:"); ascii_put(p,n); break; case 'c': puts("put in order of string's length:"); length_put(p,n); break; case 'd': puts("put in order of first word's length:"); word_put(p,n); break; case 'e': break; default : puts("Quit."); return 0; } } while( command[0] != 'e' ); } } void origin_put(char **p, int n) { int i; for(i=0; i puts(p[i]); } void ascii_put(char **p, int n) { int i,j; char *temp; for(i=0; i for(j=0; j if (strcmp( p[j], p[j+1] ) > 0) { temp = p[j]; p[j] = p[j+1]; p[j+1] = temp; } origin_put(p,n); } void length_put(char **p, int n) { int i,j; char *temp; for(i=0; i for(j=0; j if ( strlen(p[j]) > strlen(p[j+1]) ) { temp = p[j]; p[j] = p[j+1]; p[j+1] = temp; } origin_put(p,n); } int first_word_length(char *p) { int i=0; for (; !isalpha(*p); p++) if (*p == '\0') return 0; for (i=1; isalpha(p[i]); i++) continue; return i; } void word_put(char **p, int n) { int i,j; char *temp; for(i=0; i for(j=0; j if ( first_word_length(p[j]) > first_word_length(p[j+1]) ) { temp = p[j]; p[j] = p[j+1]; p[j+1] = temp; } origin_put(p,n); } 11.编写一个程序。功能是读取输入,直到遇到EOF,并报告单词数、大写字母数、小写字母数、标点符号数和数字字符数。使用ctype.h系列的函数。 #include #include int main(void) { int word=0,upper=0,lower=0,punct=0,digit=0,begin=0; char ch; while( ( ch = getchar() ) != EOF ) { if( isalpha(ch) ) { if (begin == 0) { word++; begin = 1; } } else begin = 0; if( isupper(ch) ) upper++; if( islower(ch) ) lower++; if( ispunct(ch) ) punct++; if( isdigit(ch) ) digit++; } printf("word:%d\nupper:%d\nlower:%d\npunct:%d\ndigit:%d\n",word,upper,lower,punct,digit); return 0; } 12.编写一个程序,按照相反的单词顺序显示命令行参数。即,如果命令行参数是see you later,程序的显示应该为later you see。 #include #include #include int main(void) { char str[81]; char *p, temp; int i,n,length; gets(str); for (p = str,i=0,n = strlen(str); i { temp = *(p+n-1-i); *(p+n-1-i) = *(p+i); *(p+i) = temp; } puts(str); p = str; length=0; do //将字符串中的每个单词倒序 { if( isalpha(*p) ) { length++; } else { if(length>1) for(i=0; i { temp = *(p-1-i); *(p-1-i) = *(p-length+i); *(p-length+i) = temp; } length = 0; } } while(*p++ != '\0'); puts(str); return 0; } 13.编写一个计算乘幂的基于命令行的程序。第一个命令行参数为double类型数,作为幂的底数;第二个参数为整数,作为幂的指数。 #include double mypower(double base, int exp); int main(void) { double base; int exp; printf("input base number and exp:"); scanf("%lf%d", &base, &exp); printf("%g^%d= %g\n", base, exp, mypower(base,exp) ); return 0; } double mypower(double base, int exp) { double power = 1; if (exp<0) power = 1/mypower(base, -exp); else if (exp>0) while( exp-- > 0 ) power *= base; else if(base!=0) power = 1; else power = 1/base;//0的0次幂应是一个无意义数 return power; } 14.使用字符分类函数实现atoi()函数。 #include #include #include double myatof(char *p); int main(void) { char a[30]={0}; while(a[0] != 'q') { puts("input a double without +-e:"); gets(a); printf("atof: %.5lf\n",atof(a)); printf("myatof: %.5lf\n",myatof(a)); printf("difference:%.5lf\n", atof(a) -myatof(a)); puts("input any char except q to go on."); gets(a); } puts("Quit."); return 0; } double myatof(char *p)//将字符串转换为浮点型,暂时只限小数点格式(如:342.678){ double n=0; int i=-1; while( 1 ) { if (isdigit(*p)) //如果是数字 { n = n*10 + (*p) -'0'; if(i != -1) i++; //小数位数i计数 } else if ( *p == '.' && i == -1) //如果是第一个小数点 i=0; //开启小数位数i计数 else break; p++; } for(; i>0; i--) //根据小数位数i,将n取为原来的(10^i)分之一 n /= 10; return n; } 15,编写一个程序,其功能是读取输入,直到遇到文件结尾,并把文件显示出来。要求程序可以识别并执行下面的命令行参数: ┏━━━━┳━━━━━━━━━━━┓ ┃-p ┃按照原样显示输入┃ ┣━━━━╋━━━━━━━━━━━┫ ┃-u ┃把输入全部转换为大写┃ ┣━━━━╋━━━━━━━━━━━┫ ┃-l ┃把输入全部转换为小写┃ ┗━━━━┻━━━━━━━━━━━┛ #include #include int main(int argc, char *argv[]) { char ch; if (argv[1][0] == '-') //注意argv[0]是EXE的路径,所以参数是argv[1]、argv[2]…… if (argv[1][1] == 'u') while(( ch=getchar() ) != EOF) putchar( toupper(ch) ); else if (argv[1][1] == 'l') while(( ch=getchar() ) != EOF) putchar( tolower(ch) ); else if (argv[1][1] == 'p') while(( ch=getchar() ) != EOF) putchar(ch); return 0; }