第十一章 字符串和字符串函数
编程练习
- 设计并测试一个函数,可以输入读取n个字符(包括空格、制表符、换行符),把结果存储在一个数组中,这个数组的地址通过参数来传递。
#include <stdio.h> #define LEN 80 char * getch(char a[], int n); int main(void) { char a[LEN]; if (getch(a, 4)) puts(a); else printf("没有读取\n"); return 0; } char * getch(char a[], int n) { int i; for (i = 0; i < n; i++) { a[i] = getchar(); if (EOF == a[i]) { a[i] = ‘\0‘; break; } } a[i] = ‘\0‘; if (!a[0]) return NULL; return a; }
2.修改编程练习1中的函数,使得可以在N个字符后,或第一个空格、制表、换行符后停止读取输入,由上述情况中最先满足的那个终止读取(不能用scanf()函数)。
#include <stdio.h> #include <ctype.h> #define LEN 80 char * getch(char a[], int n); int main(void) { char a[LEN]; if (getch(a, 6)) puts(a); else printf("没有读取\n"); return 0; } char* getch(char a[], int n) { int i; for (i = 0; i < n; i++) { a[i] = getchar(); if (EOF == a[i] || isspace(a[i])) { a[i] = ‘\0‘; break; } } a[i] = ‘\0‘; if (‘\0‘ == a[0]) return NULL; return a; }
3.设计并测试一个函数,其功能是读取输入行里的第一个单词到数组,并丟掉该行中其它的字符。
一个单词的定义是一个字符串,其中不含空格、制表符和换行符
#include <stdio.h> #include <ctype.h> #include <stdbool.h> //不支持bool,可以返回int类型 0 或 1 bool getword(char * ); int main(void) { char array[20]; if (getword(array)) puts(array); else puts("没有读取到单词。"); return 0; } bool getword(char * array) { char ch; int a = 0; char * p = array; while ((ch = getchar()) != ‘\n‘) { //怱略一行开始处的空格。 if (a == 0 && isspace(ch)) continue; else a = 1; if (!isspace(ch)) *array++ = ch; else break; } *array = ‘\0‘; if (*p == ‘\0‘) return false; return true; }
4.设计并测试一个函数,其功能是搜索由第一个参数指定的字符串,在其中查找由函数的第二个参数指定的字符的第一次出现的位置。如果找到,返回指向这个字符的指针;如果没找返回空字符(这种方式和strchr()函数的功能一样)。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。
#include <stdio.h> #define LEN 80 char * search(char *str, char ch); int main(void) { char ch; char target[LEN]; char * pstr; puts("请输入字符串(在一行的开始处输入回车结束):"); while (gets(target) && target[0] != ‘\0‘) { puts("请输入字符:"); ch = getchar(); while (getchar() != ‘\n‘) ; pstr = search(target, ch); if (pstr == NULL) printf("字符%c不在字符串中\n", ch); else printf("找到字符%c,它的地址为%p\n", ch, pstr); puts("请输入下一个字符串(在一行的开始处输入回车结束:"); } return 0; } char * search(char *str, char ch) { while (*str != ‘\0‘) { if (*str++ == ch) return str; } return NULL; }
5.编写一个函数is_within(),它接受两个参数,一个是字符,另一个是字符串指针。其功能是如果字符在字符串中,就返回一个非0值(真);如果字符不在字符串中,就返回0值(假)。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。
#include <stdio.h> #define LEN 80 int search(char *str, char ch); int main(void) { char ch; char target[LEN]; puts("请输入源字符串(在一行的开始处输入回车结束):"); while (gets(target) && target[0] != ‘\0‘) { puts("请输入目标字符:"); ch = getchar(); while (getchar() != ‘\n‘) ; if (search(target, ch)) printf("字符%c在字符串中\n", ch); else printf("字符%c不在字符串中\n", ch); puts("请输入下一个源字符串(在一行的开始处输入回车结束:"); } return 0; } int search(char *str, char ch) { while (*str != ‘\0‘ && *str != ch) str++; return *str; }
6.strncpy(s1, s2, n)函数从s2复制n个字符给s1,并在必要时截断s2或为其填充额外的空字符。如果s2的长度等于或大于n,目标字符串没有标志结束的空字符。函数返回s1。自己编写这个函数,并在一个使用循环语句为这个函数提供输入的完整程序中进行测试。
#include <stdio.h> #define LEN 80 char * strncpy1(char *, char *, int); int main(void) { char str1[LEN], str2[LEN]; int n; printf("请输入要复制的字符串:"); while (gets(str2)) { printf("请输入要复制的字符个数:"); scanf("%d", &n); strncpy1(str1, str2, n); printf("复制的字符串:"); puts(str1); printf("请输入要复制的字符串:"); while (getchar() != ‘\n‘) ; } return 0; } #include <string.h> char * strncpy1(char *str1, char *str2, int n) { int l = strlen(str2); int i; if (l > n) n = l; for (i = 0; i < n; i++) str1[i] = str2[i]; str1[i] = ‘\0‘; return str1; }
7.编写一个函数string_in(),它接受两个字符串指针参数。如果第二个字符串被包含在第一个字符串中,函数就返回被包含的字符串开始的地址。例如,string_in("hats", "at")返回hats中a的地址,否则,函数返回空指针。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。
#include <stdio.h> #define LEN 80 char * string_in(char *, char *); int main(void) { char str1[LEN], str2[LEN]; char * pstr; printf("请输入被查找的字符串:"); while (gets(str1)) { printf("请输入要查找的字符串:"); gets(str2); pstr = string_in(str1, str2); if (pstr != NULL) { printf("字符串已找到在内存中的地址为%p\n", pstr); } else { printf("未找到字符串。\n"); } printf("请输入被查找的字符串:"); } printf("结束!"); return 0; } #include <string.h> char * string_in(char * str1, char * str2) { int len2 = strlen(str2); int match; int len1 = strlen(str1); int i = len1 - len2 + 1; if (i > 0) { while ((match = strncmp(str1, str2, len2)) && i-- ) { str1++; } } if(match) return NULL; else return str1; }
8.编写一个函数,其功能是使输入字符串反序。在一个使用循环语句为这个函数提供输入的完整程序中进行测试。
#include <stdio.h> #define LEN 80 char * antitone(char * pstr); int main(void) { char str[LEN]; printf("请输入要反序的字符串:"); while (gets(str)) { printf("反转后的字符串:"); puts(antitone(str)); printf("请输入要反序的字符串:"); } printf("结束!\n"); return 0; } #include <string.h> char * antitone(char * pstr) { int len = strlen(pstr) - 1; int i; char temp; for (i=0, i<len - i; i++) { temp = pstr[len - i]; pstr[len - i] = pstr[i]; pstr[i] = temp; } return pstr; }
9.编写一个函数,其参数为一个字符串,函数删除字符串中的空格。在一个可以循环读取的程序中进
行测试,直到用户输入空行。对于任何输入字符串,函数都应该适用并可以显示结果
#include <stdio.h> #define LEN 80 char * del_space(char * pstr); int main(void) { char str[LEN]; printf("请输入要删空格的字符串:"); while (gets(str) && str[0] != ‘\0‘) { printf("删掉空格后的字符串:"); puts(del_space(str)); printf("请输入要删空格的字符串:"); } printf("结束!\n"); return 0; } #include <ctype.h> char * del_space(char * pstr) { char * temp = pstr; char * temp1; while (*temp) { if (isspace(*temp)) { temp1 = temp; do { *temp1 = *(temp1 + 1); } while(*++temp1) ; } else { temp++; } } return pstr; }
10,编写一个程序,读取输入,直到读入了10个字符串或遇到EOF,由二者中最先被满足的那个终止读取过程。这个程序可以为用户提供一个有5个选项的菜单:输出字符串列表、按ASCII顺序输出字符串、长度递增顺序输出字符串、按字符串中第一个单词的长度输出字符串、退出。菜单可以循环直到用户输入退出请求。当然,程序要能真正完成菜单中的各项功能。
/* * 10,编写一个程序,读取输入,直到读入了10个字符串或遇到EOF,由二者中最先被满足的那个终止读取过程。 * 这个程序可以为用户提供一个有5个选项的菜单:输出字符串列表、按ASCII顺序输出字符串、 * 长度递增顺序输出字符串、 * 按字符串中第一个单词的长度输出字符串、退出。菜单可以循环直到用户输入退出请求。 * 当然,程序要能真正完成菜单中的各项功能。 */ #include <stdio.h> #include <string.h> #include <ctype.h> #define ROWS 10 #define COLS 81 void menu(void); //显示菜单 char get_char(void); //读取用户输入的正确选项 int in_str(char str[][COLS]); //输入字符串,返回字符串的个数 void show_str(const char * str[], int n); //输出参数传递过来字符串 void show_ascii(char * str[], int n); //按ASCII顺序输出 void show_strlen(char * str[], int n); //按字符串长度输出 void show_wordlen(char * str[], int n); //按字符串第一个单词的长度输出 int wordlen(char * str); //求字符串第一个单词找度 int main(void) { char str[ROWS][COLS]; //保存输入的原始字符串,值不做改变,方便用户循环选择时,任何时候都能输出原始值。 char str_copy[ROWS][COLS]; //原始数据的备份可改变 char * pstr[ROWS]; //声明指针做为函数参数传送 char * pcopy[ROWS]; char ch; //菜单选项 int i; //字符串的个数 int j; //用于数组赋值 i = in_str(str); for (j = 0; j < i; j++) { //数组赋值 pstr[j] = str[j]; pcopy[j] = str_copy[j]; strcpy(pcopy[j],pstr[j]); } menu(); while ((ch = get_char()) != ‘q‘) { switch (ch) { case ‘a‘: show_str(pstr, i); break; case ‘b‘: show_ascii(pcopy, i); break; case ‘c‘: show_strlen(pcopy, i); break; case ‘d‘: show_wordlen(pcopy, i); break; default: printf("Error!"); } menu(); } return 0; } int wordlen(char * str) { //首单词字母个数 int count = 0; char ch; while (ch = *str++) { if (isspace(ch) && count == 0) continue; if (isspace(ch) && count != 0) break; if (!isspace(ch)) count++; } return count; } void show_wordlen(char *str[], int n) { //按照首单词字母长度排序后输出 char * temp; int i, j; for (i = 0; i < n - 1; i++) for (j = i; j < n; j++) if (wordlen(str[i]) > wordlen(str[j])) { temp = str[i]; str[i] = str[j]; str[j] = temp; } show_str(str, n); } void show_strlen(char *str[], int n) { //按照字符串长度排序后输出 char * temp; int i, j; for (i = 0; i < n - 1; i++) for (j = i; j < n; j++) if (strlen(str[i]) > strlen(str[j])) { temp = str[i]; str[i] = str[j]; str[j] = temp; } show_str(str, n); } void show_ascii(char *str[], int n) { //按照字符ASCII编码顺序排序后输出 char * temp; int i, j; for (i = 0; i < n - 1; i++) for (j = i; j < n; j++) if (strcmp(str[i], str[j]) > 0) { temp = str[i]; str[i] = str[j]; str[j] = temp; } show_str(str, n); } void show_str(const char *str[], int n) { //输出字符串数组 int i = 0; while (i < n) puts(str[i++]); } int in_str(char(*str)[COLS]) { //输入字符串 int i = 0; do { printf("请输入字符串%d(输入EOF结束): ", i + 1); } while (gets(str[i]) && ++i < ROWS); puts("输入结束。"); return i; } void menu(void) { //显示菜单 puts("请选择字符串输出方式:"); puts(" a)输出字符串列表"); puts(" b)按ASCII顺序输出字符串"); puts(" c)长度递增顺序输出字符串"); puts(" d)按字符串中第一个单词的长度输出字符串"); puts(" q)退出"); } char get_char(void) { //确认输入符合要求 char ch; while (ch = getchar()) { while (getchar() != ‘\n‘) ; if (!strchr("abcdq", ch)) puts("请输入正确的选项,(如:a b c d q):"); else break; } return ch; }
11.编写一个程序。功能是读取输入,直到遇到EOF,并报告单词数、大写字母数、小写字母数、标点符号数和数字字符数。使用ctype.h系列函数。
#include <stdio.h> #include <ctype.h> #include <stdbool.h> int main() { int count_word = 0; int count_lower = 0; int count_upper = 0; int count_digit = 0; int count_punct = 0; bool sign = false; char ch; while ((ch = getchar()) != EOF) { if (islower(ch)) count_lower++; else if (isupper(ch)) count_upper++; else if (isdigit(ch)) count_digit++; else if (ispunct(ch)) count_punct++; if (!isspace(ch) && !sign) { //单词的界定为单个非空格字符和不包含空格字符的字符串, count_word++; sign = true; } else if (isspace(ch) && sign) { sign = false; } } puts("统计结果:"); printf("单词数:%d\n", count_word); printf("小写字母数:%d\n", count_lower); printf("大写字母数:%d\n", count_upper); printf("标点符号数:%d\n", count_punct); printf("数字个数:%d\n", count_digit); return 0; }
12.编写一个程序,按照相反的单词顺序显示命令行参数。即,如果命令行参数是see you later,程序的显示应该为later you see。
#include <stdio.h> #include <string.h> #include <ctype.h> #define LEN 80 int main() { char str[LEN] = "see you later"; char temp; int len = strlen(str) - 1; int i, j, wordlen; puts(str); for (i = 0; i < len - i; i++) { temp = str[i]; str[i] = str[len - i]; str[len - i] = temp; } puts(str); wordlen = 0; i = 0; do { if (!isspace(str[i]) && str[i] != ‘\0‘) //isspace()不能识别‘\0‘条件中要加上str[i] != ‘\0‘ wordlen++; else { if (wordlen > 0) { for (j = 0; j < wordlen - j; j++) { temp = str[i -1 - j]; //i-1 位置在单词的最后一个了符 str[i - 1 -j] = str[i - wordlen+j]; //[i - wordlen]位置在单词的第一个字符。 str[i - wordlen+j] = temp; } wordlen = 0; } } } while (str[i++] != ‘\0‘); puts(str); return 0; }
13.编写一个计算乘幂的基于命令行和程序。第一个命令行参数为double类型数,作为幂的底数;第二个参数为整数,作为幂的指数。
#include <stdio.h> #include <stdlib.h> //提供atof() #include <math.h> //提供pow() int main(int argc, char *argv[]) { double num, exp; if (argc != 3) printf("参数不符\n"); else { num = atof(argv[1]); exp = atof(argv[2]); printf("%.2lf的%.0lf次幂为:%lf", num, exp, pow(num, exp)); } return 0; }
14.使用字符分类函数实现atoi()函数。
#include <stdio.h> #include <ctype.h> int main(int argc, char *argv[]) { char str[20]; while(gets(str)) printf("%d\n", my_atoi(str)); return 0; } int my_atoi(char * pstr) { int sign = 1; int num = 0; //字符串不能为空 if (pstr == NULL) return 0; //去掉空格 while (isspace(*pstr)) pstr++; //判数首位是否有符号 if (*pstr == ‘-‘) sign = -1; if (*pstr == ‘-‘ || *pstr == ‘+‘) pstr++; //转换直到遇到非数字时结束。 while (isdigit(*pstr)) { num = (num * 10) + (*pstr - ‘0‘); pstr++; } //增加符号位 num *= sign; return num; }
15.编写一个程序,其功能是读取输入,直到遇到文件结尾,并把文件显示出来,要求程序可以识别并执行下面的命令行参数:
-p 按原样显示输入
-u 把输入全部转换为大写
-l 把输入全部转换为小写
#include <stdio.h> #include <ctype.h> int main(int argc, char *argv[]) { int ch; if (argc > 2) { printf("%s不是正确的指令,请输入正确的指禽 -p -u 或-l\n", argv[1]); printf("例如: %s [-p | -u | -l]\n", argv[0]); } else if (argc == 2) { if (argv[1][0] != ‘-‘) { printf("%s不是正确的指令,请输入正确的指禽 -p -u 或-l\n", argv[1]); printf("例如: %s [-p | -u | -l]\n", argv[0]); } else switch (argv[1][1]) { case ‘p‘:while ((ch = getchar()) != EOF) putchar(ch); break; case ‘u‘:while ((ch = getchar()) != EOF) putchar(toupper(ch)); break; case ‘l‘: while ((ch = getchar()) != EOF) putchar(tolower(ch)); break; default: printf("%s不是正确的指令,请输入正确的指禽 -p -u 或-l\n", argv[1]); printf("例如: %s [-p | -u | -l]\n", argv[0]); } } return 0; }