字符串和字符数组
1、字符串
严格意义上来说,C语言并没有字符串原生的字符串的类型,而是通过字符指针来实现的:char *p = "LINUX";。而对于其他的高级语言来说,比如C++的就存在字符串类型: string p1 = "I LOVE LINUX"; 。
字符串在内存中其实就多个字节组成的,且地址都是连续的;指针指向字符串的的头部;字符串的结尾是以"\0"(是真能整的零)作为字符串结束的标志。
"\0" 的理解:
\0 是一个 ASCII 字符,其实是编码为零的字符,是真正的零。这个和数字零是不同的,数字零的 ASCII 是48。
注意:
当定义一个字符串的时候:char *p = "LINUX",系统会在这个字符串的结尾处自动添加'\0',作为结束的标志,所以'\0'虽然是连接这最后一个字符,但是并不属于这个字符串。
分配的字符串,是被保存到文字常量区
int main(int argc, char *argv[]) { char *p = "I LOVE LINUX"; printf("%c\n", *p); printf("%s\n", p); while (1); }
输出结果为:
II LOVE LINUX
2、字符数组
定义:char p[] = "I LOVE LINUX";
其实就是将字符串放到数组中,在一块连续的内存中依次排放,则数组名则是指向字符串第一个地府的地址 。
int main(int argc, char *argv[]) { char p[] = "I LOVE LINUX"; for (int i = 0; i < 12; i++) { printf("%c", *(p + i)); } while (1); }
或者也可以直接printf("%s\n", p);,输出。
字符数组是将整个字符串一次存在数组中,以上面为例,其实就是一个12个元素的数组。char p[12]={'I','','L','O','V','E','','L','I','N','U','X'},12 个元素依次排放。
注意: 因为是字符串,所以字符串结尾的地方编译器也是会自动添加 \'0,所以char *P[],里面其实是13个字节,分配的字符数组,是被分配到堆中。
3、sizeof、strlen与字符串、字符数组
sizeof:
是 C 语言的运算符,计算变量的所占据的内存空间的大小。
strlen:
是函数,计算字符串的长度。遇到'\0'就结束。
计算:
char str[20] = "0123456789"; int a = strlen(str); ubt b = sizeof(str);
a = 10,因为strlen() 是计算字符串的长度的函数,当遇到‘\0’就结束,所以得到的数值是10
b = 20 ,因为sizeof 函数是计算分配内存空间的大小的,很显然数组是分配了20个字节,所以得到的就是20了。
char *str1 = “abcde”; char str2[] = "abcde"; char str3[8]={'a',}; char str4[] = "0123456789"; sizeof(str1); // 4 sizeof(str2); // 6 sizeof(str3); // 8 sizeof(str4); // 11
分析,首先可以知道sizeof 函数是计算分配内存空间大小的。str1 显然就是一个指针嘛,不论怎么样,只占所占的字节数,永远都是四个字节;str2 是字符数组,虽然字母是五个,但是必须知道字母的后面接有一个看不见的'\0'作为字符串的结束的标志,所以就总共了6个字符,所以就是6个字节了;str3 显然已经定义了数则的长度是8,所以只能是八个字节;str4 显然也是一个字符数则,十个字符加上一个'\0'字符串结束标志,总共11个字符,所以11个字节。
4、C语言和字符串处理函数
C语言: char st[100]
(1)字符串的长度
strlen(st)
(2)字符串的比较
strcmp(st1,st2); // 全部比较 strncmp(st1,st2,n); // 比较前面 n 个
(3)附加
strcat(st1,st2) strncat(st1,st2,n); // st2 的前面 n 个连接到 st1
(4)拷贝
strcpy(st1,st2); strncpy(st1,st2,n); // 复制 st2 前面的 n 个字节到 st1
(5)查找
where = strchr(st,ch) ch为要找的字符。 where = strspn(st1,st2); 查找字符串。
5、字符串的操作
(1)字符串的长度
例子1:
int strlen_v1(char *src) { char *y = src; while (*y++); return (y - src -1); }
因为字符串在内存中都是连续进行排放的,所以可以通过计算地址的方式进行计算。这里需要注意: *y++ 的计算顺序(*y++ 与(*y)++ 会在其他
的地方做总结)。*y 计算的是每个字符的值,当不等于字符串的结束符之前('\0'),则一直向后移动一个,当移动到'\0'的时候,这个时候显然是不成立的,但是y 还是要接着向后移动一个,所以字符串的长度就是,y - src -1。这里与不用 *y++ 做对比:
int strlen_v1(char *src) { char *y = src; while (*y) { y++; } return (y - src); }
例子2:
int strlen_v2(char *src) { int i = 0; char *y = src; while (*y) { i++; y++; } return i; }
当 *y 等于\0 的时候,就会被退出,返回 i 值,就是字符串的长度。
(2)字符串比较函数
int strcmp_v1(char *string1, char *string2) { // 重新赋值指针,不要改变原先的指针 char *str1 = string1; char *str2 = string2; while ((*str1) && (*str2) && (*str1 == *str2)) { str1++; str2++; } if ( *str1 > *str2) { return 1; } if (*str1 < *str2) { return -1; } else return 0; }
(3)附加: 将字符串 str2 接到 str1 的后面
char * stringstring(char * str1, char *str2) { char *s1 = str1; char *s2 = str2; while (*s1) s1++; while (*s2) { *s1 = *s2; s1++; s2++; } *s1 = '\0'; return str1; } int main(int argc, char *argv[]) { char p[] = "LINUX"; char pp[] = "I LOVE"; printf("%s\n", stringstring(pp,p)); while (1); }
s1结束的时候是执行字符串的 '\0',所以附加的字符就在这个地方开始进行字符串的拷贝。当 s2 结束的时候,完成了所有字符的拷贝,所以在结束的位置添加字符串结束的标志 '\0' 。这里注意到主函数使用的是字符数组而不是字符串,原因是字符串的话,这些字符串是被存放到文字常量区,这个区域是只读的区域,指针指向了文字常量区,可以访问,但是完全不可以对其进行写的操作;而以字符数组的方式的话,是被分配到栈中的,对于栈的操作是可读可写的操作。
(4)字符串的拷贝
void strcpy_v1(char *dest, char *src) { char *d = dest; while (*src) { *d++ = *src++; } *d = '\0'; } int main(int argc, char *argv[]) { char src[] = "I LOVE LINUX"; char dest[13]; strcpy_v1(dest, src); printf("%s\n", dest); while (1); }
需要对字符串进行写操作,所以还是必须以字符数组的方式进行定义,不能以字符串的方式进行定义。
(6)实现字符串str1中查找str2,返回找到的地址
char * mystrstr(char * str1, char *str2) { if (str2 == NULL) { return nullptr; } char *p = str1; while (*p) { char *p1 = p; char *p2 = str2; while ((*p1) && (*p2) && (*p2 == *p1)) { p1++; p2++; } if (!*p2) return p; p++; } return nullptr; } int main(int argc, char *argv[]) { char src[] = "I LOVE LINUX"; char dest[] = "LINUX"; printf("%s\n", mystrstr(src, dest)); while (1); }
(7)实现字符串的反转
void strRev(char *s) { char *rev = s; char temp; // 让 rev 指针直到最后一个字符串的字母 char *end = rev + strlen(rev) - 1; while (end > rev) { temp = *rev; *rev = *end; *end = temp; end--; rev++; } }