字符串的概念
- 字符串是有序字符的集合
- 字符串是程序中的基本元素之一
- C 语言中没有字符串的概念
- C 语言中通过特殊的字符数组模拟字符串
- C 语言中的字符串是以 ‘\0’ 结尾的字符数组(’\0’ 表示字符串的结束)
字符数组与字符串
在 C 语言中,双引号引用的单个或多个字符是一种特殊的字面量
- 存储与程序的全局只读存储区
- 本质为字符数组,编译器会自动在结尾加上 ‘\0’ 字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
#include <stdio.h> int main() { char ca[] = {'H', 'e', 'l', 'l', 'o'}; char sa[] = {'W', 'o', 'r', 'l', 'd', '\0', '1', '2'}; char ss[] = "Hello World!"; char* str = "Hello World!";
printf("%s\n", ca); printf("%s\n", sa); printf("%s\n", ss); printf("%s\n", str);
}
|
- 字符串字面量的本质是一个数组
- 字符串字面量可以看作常量指针
- 字符串字面量中的字符不可改变
- 字符串字面量至少包含一个字符(’\0’)
字符串字面量
Hello World! 是一个无名的字符数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| #include <stdio.h>
int main() { char b = "abc"[0]; char c = *("123" + 1); char t = *"";
printf("%c\n", b); printf("%c\n", c); printf("%c\n", t);
}
|
字符串的长度
- 字符串的长度就是字符串所包含字符的个数
- 字符串长度指的是第一个 ‘\0’ 字符前出现的字符个数
- 通过 ‘\0’ 结束符来确定字符串的长度
- 函数 strlen 用于返回字符串的长度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| #include <stdio.h> #include <string.h>
int main() { char s[] = "Hello\0World"; int i = 0;
for(i = 0; i < sizeof(s) / sizeof(char); i++) { printf("%c\n", s[i]); }
printf("%ld\n", sizeof(s)); printf("%ld\n", strlen(s)); printf("%ld\n", strlen("123"));
}
|
当 sizeof() 用于计算字符串长度时会包含其中的 \0;
小结
- C 语言中通过字符数组模拟字符串
- C 语言中的字符串使用 ‘\0’ 作为结束符
- 字符串字面量的本质为字符数组
- 字符串相关函数都依赖与结束符 ‘\0’
字符串中的一些典型问题
1 2 3 4 5 6 7 8 9 10 11 12
| #include <stdio.h> int main() { char buf[10] = {0}; char src[] = "Hello %s";
snprintf(buf, sizeof(buf), src);
printf("buf = %s\n", buf);
}
|
snprintf
是 C 标准库中的一个函数,用于格式化输出字符串,并将结果存储在一个缓冲区中。
int snprintf(char *str, size_t size, const char *format, …);
str
: 指向要存储格式化字符串的字符数组(目标缓冲区)。
size
: 指定写入 str
的最大字符数,也就是 str 的大小(包括终止的空字符 \0
)。
format
: 类似于 printf
的格式化字符串,用于指定输出的格式。
…: 可变参数,用于指定格式化字符串中的实际值。
注意:
上述输出总为什么会打印 乱码,而不是 %s 呢?
因为当 snprintf 函数只有 3 个参数时,如果第三个参数没有包含格式化信息,函数调用没有问题;相反,如果第三个参数包含了格式化信息,但缺少后续对应参数,则程序行为不确定;
解释一下,他是类似 ptinrf 的,当我们第三个参数包含 %s 时,他会认识是后续有内容需要按照 %s 的格数输出,但我们其实是没有的,所以在打印的时候这里的 %s 就是一个未知的内容了;
可改为:snprintf(buf, sizeof(buf), “%s”, src);,或者将 %s 改为其他的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| #include <stdio.h> #include <string.h>
#define STR "Hello, \0Kay.Wang\0"
int main() { char* src = STR; char buf[255] = {0};
snprintf(buf, sizeof(buf), "%s", src);
printf("strlrn(STR) = %ld\n", strlen(STR)); printf("sizeof(STR) = %ld\n", sizeof(STR));
printf("strlrn(src) = %ld\n", strlen(src)); printf("sizeof(src) = %ld\n", sizeof(src));
printf("strlrn(buf) = %ld\n", strlen(buf)); printf("sizeof(buf) = %ld\n", sizeof(buf));
}
|
- 字符串相关的函数均以第一个出现的 ‘\0’ 作为结束符
- 编译器总是会在字符串字面量的末尾添加\0
- 字符串字面量的本质为数组
字符串、字符数组、字符指针三者本质上是不同,但是互相之间又有一定的关系
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <stdio.h> #include <string.h>
#define S1 "Hello, \0Kay.Wang\0" #define S2 "Hello, \0Kay.Wang\0"
int main() { if (S1 == S2){ printf("Equal\n"); } else { printf("Non Equal\n"); } if(strcmp(S1, S2) == 0) { printf("Equal\n"); } else { printf("Non Equal\n"); } }
|
编译器会将相同的字符串优化为一个,也就说 S1、S2引用的是痛同一个字符串,所以二者直接进行比较时,是相同的,因为地址相等;
- 字符串之间的相等比较需要使用 strcmp 完成
- 不可直接用 == 进行字符串直接的比较
- 完全相同的字符串字面量的 == 比较结果为 false
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| void right_shift_r(const char* src, char* result, unsigned int n);
#include <stdio.h> #include <string.h>
void right_shift_r(const char* src, char* result, unsigned int n) { const unsigned int LEN = strlen(src); int i = 0; for(i=0; i < LEN; i++) { result[(n + i) % LEN] = src[i]; } result[LEN] = '\0'; }
int main() { char result[255] = {0}; right_shift_r("abcde", result, 2); printf("%s\n", result); right_shift_r("abcde", result, 5); printf("%s\n", result); right_shift_r("abcde", result, 8); printf("%s\n", result); return 0; }
|