《C Primer Plus》 学习笔记系列之(二)

秒速五厘米 2022-08-23 11:52 255阅读 0赞

第11章 字符串和字符串函数

下面的程序使用了gets()和puts(), 以及字符指针的用法:

  1. #include<stdio.h>
  2. #define LIM 5
  3. #define LINELEN 81 //最大字符串长度
  4. #define MSG "You must have many talents.Tell me more." //定义字符串常量
  5. int main()
  6. {
  7. char name[LINELEN];
  8. char talents[LINELEN];
  9. const char m2[] = "If you can't think of anything, fake it'";
  10. const char *m3 = "\nEnough about me - what's your name?"; //初始化一个指针
  11. const char * mytal[LIM] = { //mytal[1] mytal[2] mytal[3] mytal[4] mytal[5] 分别指向不同的字符串
  12. "Multiplying accurately", "stashing data", "Adding numbers swiftly", "Following instructions to the letter",
  13. "Understanding the c language"
  14. };
  15. int i;
  16. for (i = 0; i < LIM; i++)
  17. {
  18. puts(mytal[i]); //使用puts()输出字符串
  19. }
  20. puts(MSG);
  21. puts("Your name:");
  22. gets(name);
  23. puts("Yours more talents:");
  24. gets(talents);
  25. printf("%s\n%s\n", name, talents);
  26. return 0;
  27. }
  28. #include<stdio.h>
  29. int main()
  30. {
  31. char title[30];
  32. while (gets(title) != NULL && title[0] != '\0')
  33. {
  34. puts(title);
  35. }
  36. return 0;
  37. }

gets()试图超过文件结尾读取字符,这个表达式的值为NULL。如果用户在输入行的开始就按了回车键,将输入空字符串,以结束循环。

字符串常量属于静态存储(static storage)类。静态存储是指如果在一个函数中使用字符串常量,即使是多次调用了这个函数,该字符串在程序的整个运行过程中只存储一份。

整个引号中的内容作为指向该字符串存储位置的指针。这点与把数组名作为指向数组存储位置的指针类似。下面的程序可以证明这一点:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. //整个字符串的内容,"Jack Chou"是作为指向该字符串存储位置的指针
  5. printf("%s, %p, %c\n", "Hello", "Jack Chou", *"Jack Chou");
  6. return 0;
  7. }

//运行后的结果:
Hello, 0x80484fc, J

数组与指针的区别:

在指定字符数组大小的时候,一定要确保数组元素比字符串长度至少多1(多出来的一个元素用于容纳空字符)。未被使用的元素均被自动初始化为0。这里
的0是char形式的空字符,而不是数字0。

通常,被引用的的字符串存储在可执行文件的数据段部分;当程序被加载到内存中时,字符串也被加载到内存中。被引用的字符串被称为位于静态存储区。

但是在程序开始运行后才为数组分配存储空间。这时候,把被引用的字符串复制到数组中。

char m3[] = “Enough about me - what’s your name?”
char *m3 = “Enough about me - what’s your name?”
在数组形式中,m3是一个地址常量,不允许使用++m3,增量运算符只能用在变量名前,而不能用在常量前。
指针形式(*m3),这个变量初始时指向字符串的第一个字符,++m3则指向第二个字符。

总之,数组初始化是从静态存储区把一个字符串复制给数组,而指针初始化只是复制字符串的地址。

只有指针才可以使用增量运算符:
char * head = “I Love Dog!”;
while ( *(head) != ‘\0’)
{
putchar(*(head++));
}

字符串的输入:

gets()函数,如果输入顺利,它返回的是读入字符串的地址;如果出错或gets()遇到文件结尾,它就返回一个空(或0)地址。
这个地址被称为空指针, 并用stdio.h里定义的常量NULL来表示。所以:
while (gets(name) != NULL){}
对于getchar()
while ((ch = getchar()) != EOF){}

gets()的一个不足是它不检查预留存储区能够容纳实际输入的数据。多出来的字符简单的溢出到相邻的内存区。
fgets()函数改进了这个问题,它需要三个参数:

  1. #include<stdio.h>
  2. #define MAX 20
  3. int main()
  4. {
  5. char name[MAX];
  6. char * ptr;
  7. ptr = fgets(name, MAX, stdin); //做多读取MAX-1个字符,或读完一个换行符为止,stdin说明读取的是键盘数据。
  8. printf("%s, %s hello", name, ptr);
  9. return 0;
  10. }

fgets()读取到换行符,会把它存到字符串里,不会像gets()函数那样把它丢掉。
对于scanf()和gets(),scanf()使用两种方法决定输入结束:
输入的字符串都是以遇到的第一个非空白字符开始。如果使用%s格式,字符串读到(但不包括)下一个空白字符(比如空格、制表符或换行符)。
如果指定了字段宽度,比如%10s,scanf()会读入10个字符或直到遇到第一个空白字符。scanf()返回一个成功读取项目的一个数值,或当遇到文件结束时返回一个EOF。

  1. #include<stdio.h>
  2. int main()
  3. {
  4. float cost;
  5. scanf("%f", &cost);
  6. return 0;
  7. }
  8. /*
  9. 运行这段代码,在心显示器的终端输入
  10. 12.50[enter]
  11. 会传送下面的字符序列:
  12. 12.50\n
  13. scanf()函数读入了1 2 . 5 0,把\n留在了输入流中,等待下一个读入语句处理。
  14. 按下回车键后,12.50\n在缓冲区中,scanf()函数将缓冲区中的12.50给读走了,剩下'\n'
  15. 于是可以使用下面这段代码来清空缓冲区:
  16. while (getchar() != '\n')
  17. {
  18. continue;
  19. }
  20. */

字符串的输出:

c有三个用于输出字符串的标准库函数:puts()、fputs()、printf()
对于puts()函数,只要给出字符串参数的地址,就可以输出字符串。
fput()需要第二个参数说明要写的文件。可以使用stdout作为参数进行输出。
char line[81];
while(fgets(line, 81, stdin))
{
fputs(line, stdout);
}
puts()和gets()一起使用而设计的,
fputs()和fgets()一起使用而设计。

自定义字符串的输出:
  1. #include<stdio.h>
  2. void put1(const char * string) //这个函数不用并不改变字符串,所以使用const修饰符
  3. {
  4. while(*string != '\0') //while(*string)
  5. {
  6. putchar(*string++); //++比*的优先级高
  7. }
  8. }

字符串函数

c库提供了许多处理字符串的函数,ANSI C用头文件string.h给出这些函数的原型。

strlen()

得到字符串的长度

strcat()

接收两个字符串参数,它将第二个字符串的一份拷贝添加到第一个字符串的结尾,从而使第一个字符串成为一个新的组合字符串,
而第二个字符串没有改变。
char flower[50] = “Rose”;
char addon[] = “s smell like old shoes”;
strcat(flower, addon);
puts(flower); //将输出连接后的字符串

strncat()

strncat(flower, addon, 10); //把addon字符串中的内容添加到flower上,直到加到10个字符或空字符为止。

strcmp()

接收两个字符串参数,如果两个字符串参数相同,就返回0。
strcmp(flower, addon);

strncmp()

可以比较到字符串的不同处,也可以比较完由第三个参数指定的字符数。
如下面的程序如果想搜索以”astro”开头的字符串,可以限定搜索前5个字符

  1. char * list[5] = {"astronomy", "astrounding", "astrophysics", "ostracize", "asterism"};
  2. int count = 0;
  3. int i;
  4. for (i = 0; i < 5; i++)
  5. {
  6. if (strncmp(list[i], "astro", 5) == 0) //指定比较前5个字符
  7. {
  8. printf("Found:%s\n", list[i]);
  9. count++;
  10. }
  11. }
  12. printf("The list contained %d words beginning with astro.\n", count);

strcpy()

复制字符串,在字符串运算中的作用等价于赋值运算符
char qwords[] = “this is a test.”;
char temp[30];
strcpy(temp, qwords); //strcpy(temp, “Hi, jack”); //根据赋值语句的顺序,左边目标字符串在左边
声明一个数组将为数据分配存储空间,而声明一个指针只为一个地址分配存储空间。
strcpy()是char *类型,它返回的是第一个参数的值,及一个字符的地址。
见下面的程序:

  1. #include<stdio.h>
  2. #include<string.h>
  3. #define WORDS "beast"
  4. #define SIZE 40
  5. int main()
  6. {
  7. char * orig = WORDS;
  8. char copy[SIZE] = "Be the best that you can be.";
  9. char * ps;
  10. puts(orig);
  11. puts(copy);
  12. ps = strcpy(copy + 7, orig); //ps指向copy的第8个元素,索引为7.orig中的'\0'正好把that中的't'给覆盖
  13. puts(copy); //遇到了前面被复制进去的空字符'\0',空字符就标志着字符串的真正结束。所以就不输出copy后面的内容了
  14. puts(ps); //ps指向copy的第8个元素
  15. return 0;
  16. }

strncpy()

需要使用第三个参数来指明最大可复制的字符数

头文件stdio.h支持的sprintf()函数

写到字符串里,而不是输出到屏幕显示。

选择法排序(字符串排序):

使用选择法进行排序,下面是一个程序实例:

  1. #include<stdio.h>
  2. int main()
  3. {
  4. //选择法排序
  5. int arr[10] = {10, 9, 3, 5, 8, 1, 2, 4, 0, 6};
  6. int i, j, temp;
  7. for (i = 0; i < 9; i++)
  8. {
  9. for (j = i + 1; j < 10; j++)
  10. {
  11. if (arr[i] > arr[j]) //以从小到大的顺序进行排序
  12. {
  13. temp = arr[j];
  14. arr[j] = arr[i];
  15. arr[i] = temp;
  16. }
  17. }
  18. }
  19. //输出那个数组
  20. int k;
  21. for (k = 0; k < 10; k++)
  22. {
  23. printf("%d\t", arr[k]);
  24. }
  25. putchar('\n');
  26. return 0;
  27. }

命令行参数

看一个例子:

  1. #include<stdio.h>
  2. int main(int argc, char *argv)
  3. {
  4. int count;
  5. printf("The commnd line has %d arguments.\n", argc - 1);
  6. printf("The command is:\n");
  7. for (count = 1; count < argc; count++)
  8. {
  9. printf("%s\n", argv[count]); //%s需要提供字符串的地址作为参数
  10. }
  11. return 0;
  12. }

SouthEast

argc是整型数,其值是命令行的单词个数;argv是一个指针,指向一个char指针数组。

发表评论

表情:
评论列表 (有 0 条评论,255人围观)

还没有评论,来说两句吧...

相关阅读