指针与字符串


在〈字符数组与字符串〉谈过 C 风格字符串,本质上就是个字符数组,而数组名称具有指针性质,那可以如下创建字符串吗?

char *text = "hello";

gcc没提出任何警讯,然而text存储了字符串常量的地址值,字符串常量创建的内容是只读的,如果试图透过text改变字符,会发生不可预期的结果:

char *text = "hello";
text[0] = 'H';        // 不可预期

因此对于字面常量,建议加上const

const char *text = "hello";

如此一来,试图透过text改变字符,编译器会失败,从而避免了执行时期的错误。

上述方式中,text只是个类型为const char*的指针,是与以下不同的,底下创建的text内容并不是只读的,因为text是个数组,text是将"hello"复制至各索引处:

char text[] = "hello";

对于wchar_t等其他为了支持 Unicode 的类型,都有这类特性。

然而,无论是哪个形式,都可以传递地址,例如:

char text1[] = "hello";
const char *text2 = "hello";

const char *text = text1; // OK
text = text2;             // OK

不过,底下不行:

char text1[] = "hello";
const char *text2 = "hello";

char *text = text1; // OK
text = text2;       // error: invalid conversion from 'const char*' to 'char*'

错误该行如果真的想通过编译,就必须明确告诉编译器,你要去除const修饰:

char text1[] = "hello";
const char *text2 = "hello";

char *text = text1;   // OK
text = (char*) text2; // 强制去除 const

会需要这么做的情况,可能是在使用一些旧的函数,它们在参数上定义的是char*,而不是const char*

那么,如何创建字符串数组呢?

#include <stdio.h>

int main(void) {
    const char *names[] = {"Justin", "Monica", "Irene"};

    for(int i = 0; i < 3; i++) {
        const char *name = names[i];
        printf("%s\n", name);
    }

    return 0;
}

留意一下底下的不同:

const char *names1[] = {"Justin", "Monica", "Irene"};
char names2[][10] = {"Justin", "Monica", "Irene"};

name1的每个元素,存储了各个字符串常量的地址值;然而,name2是有三个长度为 10 的char数组,并复制了各个字符串常量的char

可以透过typedefconst char*创建别名,令字符串数组的创建易读、易写一些:

#include <stdio.h>

typedef const char* String;

int main(void) {
    String names[] = {"Justin", "Monica", "Irene"};

    for(int i = 0; i < 3; i++) {
        String name = names[i];
        printf("%s\n", name);
    }

    return 0;
}




展开阅读全文