1. 字符串
C语言中字符串的处理是非常重要的。
可以使用char直接定义一个单个字符,使用单引号('')初始化,用%c可以将单个字符输出:
1 | char c = 't'; |
字符串本质上来说是一个由字符组成的数组,类型是char[],字符串可以储存由多个字符组成的字符序列,用大括号加双引号({""})或直接用双引号("")初始化,用%s可以将字符串输出,直接传入数组名即可:
1 | char str[] = "Hello"; // 实际的字符数组:{'H', 'e', 'l', 'l', 'o', '\0'} |
C语言中,字符串的结尾必定是\0,如果结尾丢失\0,会导致意料之外的问题。
1 | char str1[6] = "Hello"; // 正确,数组长度足以存储字符串和终止符 |
因此定义字符串时一般不会显式指定字符数组的长度,应该使用和数组类似的特性,直接让编译器自行计算长度,这样可以防止手动计算出错。
微软在处理字符串问题时,推荐使用带_s后缀的函数,例如对于字符串读取,微软推荐使用scanf_s而不是scanf,这种新的函数对字符串有特殊处理,可以避免出现字符串的未定义行为。
字符串也可以使用指针定义,与数组的指针类似,字符串的指针可以理解为指向字符数组中第一个字符的指针。
指针定义的字符串同样可以使用%s输出,但输出时与其他类型的指针不同,不需要有解引用符(*),直接将指针传入即可。
1 | char* ptr_str = "Hello!"; // 指向字符串常量的指针 |
需要注意的是,使用指针定义的字符串,其指针指向的是字符串常量,因此不可以修改单个字符,强制修改会导致未定义行为,且编译器不会显式报错,非常危险。
1 | ptr_str[0] = 'h'; // 未定义行为,字符串常量不可修改,可能会导致程序崩溃 |
想要修改指针定义的字符串时,只能直接修改指针,使其直接指向另一个字符串常量:
1 | ptr_str = "world!"; // 指针可以指向另一个字符串常量 |
一般情况下,字符串定义后不会再进行修改,因此字符串会定义为const常量字符数组类型,或者在定义指针字符串的时候显式写上const关键字。
1 | const char str[] = "Hello"; |
这样定义的话,修改字符串中的某个字符时,编译器会显式报错,更为安全。
如果不加
const常量类型,使用字符数组定义的字符串可以直接单独修改其中的字符。
1 str[0] = 'h';此外,如果定义字符指针指向定义好的指针数组,通过指针可以实现字符的修改,这个与其他类型的数组类似。
1
2
3 char str[] = "Hello";
char* ptr_str = str;
ptr_str[0] = 'h'; // 修改指针指向的内容同样也可以使用这个特性结合指针加法遍历字符串数组:
1
2
3
4
5
6
7 char str[] = "Hello";
char* ptr_str = str;
while (*ptr_str != '\0'){
printf("%c\n", *ptr_str);
ptr_str++;
}
因此,如果想要定义一个需要修改的字符串,应该使用字符数组来定义,要么隐式定义,要么定义的数组长度应满足最大长度要求。
当字符数组的长度大于有效值时,字符串的结尾以及其他无效字符均为\0。
如果想要定义一个不需要修改的字符串,可以使用const指针定义,也可以定义为const常量类型的字符数组,在修改时会有明显的报错,可读性更强。


