一个FLAG #22# cstring(1)
例子
1、scanf VS. getchar
#include <cstdio> #include <cstring> int main() { char s[20]; while (scanf("%s", s) == 1) { printf("echo: %s\n", s); } // 但是 scanf 会把换行、TAB、空格等全部忽略 // 特定情况,可采用 getchar() 来解决这个问题 // Ctrl + Z 进入下一个 while 循环 int c; while ((c = getchar()) != EOF) { printf("echo: %d - %c\n", c, c); } // 无论怎么输入,输出的最后一行总是 echo: 10 - 然后换两次行 // 是因为我们输入的最后一个字符总是换行符 \n // 而 10 恰好对应着 \n return 0; }
2、如何存储字符串字面量
本质而言,C语言把字符串字面量作为字符数组来处理。
C语言编译器在程序中遇到长度为 n 的字面量时,会为其分配长度为 n + 1 的内存空间。
既然是作为字符数组来处理,那么编译器会把字符串字面量看作是 char * 类型的指针。
#include <cstdio> int main() { char *s1 = "Hello world\n"; // [Warning] deprecated conversion from string constant to 'char*' const char *s2 = "Hello world\n"; // printf 函数的首个参数类型为 const char * printf(s1); printf(s2); printf("Hello world\n"); // 字符串字面量看作 char * 类型指针 return 0; }
3、初始化字符串变量
#include <cstdio> int main() { char s1[5] = "hi"; char s2[5] = {'h', 'i'}; // 两种初始化方式,效果上是等价的 // 余下元素被初始化为 0 也就是 '\0' printf("s1 = %s\n", s1); printf("s2 = %s\n", s2); // 但是,要注意! // char s3[5] = "hi123"; 是不可的,没有给空字符留位子,必须确保数组长度比初始化式的长度 // [Error] initializer-string for array of chars is too long [-fpermissive] char s4[] = "hi"; // 自动分配 3 个空间,分别存储 'h', 'i', '\0' printf("s4 = %s\n", s4); return 0; }
4、字符数组 VS. 字符指针
#include <cstdio> int main() { // 字符数组可修改! char s1[] = "i hate u !\n"; s1[2] = 'l'; s1[3] = 'o'; s1[4] = 'v'; s1[5] = 'e'; printf(s1); // => i love u ! // 字符指针不可以! char *s2 = "i hate u !\n"; // 编译报Warning // deprecated conversion from string constant to 'char*' // s2[2] = 'x'; 可编译但是不可执行 printf(s2); // => i hate u ! const char *s3 = "i hate u !\n"; // 正确的姿势 printf(s3); // => i hate u ! // 一个实验。这样是可行的! char s4[] = "i hate u !\n", *s5; s5 = s4; s5[2] = 'i'; printf(s5); // => i iate u ! // 以及之前声明的 const char *s3 s3 = s4; // s3[2] = 'b'; 但是不可更改!报Error 这是因为 s3 是一个 指向const char 的指针 // 它限制了对 字符数组的操作。 printf(s3); // => i iate u ! return 0; }
参考
[1] 紫书p45 TeX中的引号
[2] 《C语言程序设计_现代方法 第2版》 第13章 字符串