0%

字符串,字符数组,字符指针

字符, 字符数组, 字符指针和字符串.

上回说到, 有一种很常见的情境下我们一直在使用字符数组, 但调用函数的时候并没有传入数组的大小. 这个情景就是字符串.

实际上, c语言标准中并没有所谓的”字符串”类型, 所谓的字符串都是一定字符数组.

调用字符串相关函数的时候, 传入的都只是数组名字, 正如上篇推送所说的, 对于接受数组为参数的函数, 参数实际上是指针. 字符串相关函数都只是读取指针指向的值, 让指针+1, 等到指针指向的值为'\0'为止. 因此, 字符串必须以\0结尾.

也正因为如此, 一个字符指针可以作为参数传入如puts等相关函数. 如, 对于一个字符串数组(char的二维数组)char data[100][100], data[0]是这个二维数组的第0个元素, 也就是一个一维数组 (char [100]). data[0]就是指向这个一维数组首元素的指针. 比如, 求这个字符串数组中最长的一个字符串可以这么做:

char * getLongest(char strs[][200], int n){
    注释: 还记得为啥要写第二维的大小吗?
    char * ret = strs[0];
    int i = 0;
    for(i = 0; i < n; ++ i){
        if(strlen(s[i]) > strlen(ret)){
            ret = s[i];
        }
    }
    return ret;
}

值得注意的是, 返回的ret是一个指向字符串数组(char的二维数组)中的某个字符串的首元素的地址, 并不是复制了一份字符串返回. 如果修改了原先字符串数组中的值, 从ret指针读取到的值也会一样改变.

在字符串数组中, 漏写\0会引发更加奇怪的问题. 对于以下代码:

char strs[5][5] = {'\0'};
int i,j;
for(i = 0; i < 5; ++ i)
    for(j = 0; j < 5; ++ j){
        strs[i][j] = '*';
    }
for(i = 0; i < 5; ++ i){
    puts(strs[i]);
}

他会输出什么内容呢? 大概率是类似下面这样的东西:

*************************乱码乱码乱码
********************乱码乱码乱码
***************乱码乱码乱码
**********乱码乱码乱码
*****乱码乱码乱码

为什么会出现这种现象呢?

左滑查看答案--------------------------> puts函数会从传入的指针 
左滑查看答案--------------------------> 开始往后遍历输出, 遇到\0
左滑查看答案--------------------------> 才停止输出. 因此, 当他从strs[0][0]
左滑查看答案--------------------------> 打印到strs[0][4], 
左滑查看答案--------------------------> 下一个字节实际上是strs[1][0], 
左滑查看答案--------------------------> 仍然不是\0. 后面的几个字符串被
左滑查看答案--------------------------> 打印了好几次. 当打印完全部字符串后, 
左滑查看答案--------------------------> puts会接着往后打印, 由于后面是
左滑查看答案--------------------------> 未初始化的内存, 因此打印出来乱码, 
左滑查看答案--------------------------> 直到某个地方恰巧为\0才停止.

还有一个有意思的问题, 那就是以下代码是什么意思:

char str[100];
gets(str);
char * p = str;
while (*p){
    ...
    do something...
    ...
    ++p;
}

我们来逐层分析这一句: p是一个指向char*的指针, *p是这个char变量所存储的值. while(*p) 就是当这个char变量存储的值不为0的时候继续循环. (非0就是真). 又由于'\0的ascii码是0, 因此, 这句话的全部意思是当p指向的char为\0时退出循环.

下面是附录: 增强可读性后的几个字符串相关函数的实现.

int strlen(char *org)
{
    char *s = org;
    while (*s){
        s++;
    }
    s = s - 1;
    return s - org;
}
char *strcpy(char *ret, char *s2)
{
    char *s1 = ret;
    while ((*s1 = *s2) != '\0'){
        s1++;
        s2++;
    }
    return ret;
}
char *strcat(char *ret, char *s2)
{
    char *s1 = ret;
    while (*s1 != '\0'){
        s1++;
    }
    s1--;
    while (*s1 = *s2){
        s1++;
        s2++;
    }
    return ret;
}

欢迎关注我的其它发布渠道