一、字符串数组

char buf[] = "hello world";

字符串中所有的字符都放在数组空间中

二、字符串常量

1. 例1

char *p = "hello";

p是一个指针变量,是存放不下"hello"整个字符串的,所以"hello"被存放在了.rodata中,
.rodata存储区域是只读的,所以"hello"为只读的“字符串常量”

初始化时,整个"hello"代表是第0个元素空间的指针(也叫字符串指针),放到了指针变量p

2. 例2

printf("%s\n", "hello");

"%s\n""hello"都是字符串常量,只不过"%s\n"被用于说明输出格式,
由于字符串常量"%s\n""hello"整个就代指字符串指针,
在将字符串常量直接传递给printf函数时,其实是将“字符串指针”传递给printf函数

3. 字符串常量的特点

特点1:

是一片连续空间的一维数组,只是空间开辟在了.rodata区域中

事实上只要是一片连续的空间,我们都可以认为是数组,都可以以数组方式来访问,
不要认为只有int buf[10]这种带有[]的定义形式才是数组

字符串常量自然也是一个数组,所以完全可以以数组的形式来访问。

#incldue <stdio.h>

int main(void)
{
    char *p = "hello"; 

    int i = 0;
    for(i=0; p[i]!='\0'; i++)
    {
        printf("%c\n", p[i]); //等价于*(p+i)
    }

    return 0;
}

事实上,由于"hello"整个就代表字符串指针(第0个元素的指针),
所以printf("%c\n", p[i]);完全等价于printf("%c\n", "hello"[i]);


特点2
字符串常量放在了.rodata中,而.rodata又是只读的,不能被改写,如果强行改写的话,会导致指针错误

"hello"[3] = 'u'; // 是常量,所以是无法修改的;汇报指针错误

尝试将第3个字符'l'改为'u'会导致指针错误,显然这个是错误的

4. 再举一个例子

char *fun1(void)
{
    char buf[] = "hello"; // 是一个局部变量,函数结束,就会销毁

    return buf;
}

char *fun2(void)
{
    char *p = "hello";  // 是一个常量,函数结束,hello还在常量区

    return p;
}

int main(void)
{
    char *ret1 = NULL;
    char *ret2 = NULL;

    ret1 = fun1(); // 返回的指针指向的变量空间已经回收,所以得到的值不一定正确
    ret2 = fun2(); // 指针指向的是常量,所以正常

    return 0;
}

fun1中的buf的空间在栈中,前面就说过返回开辟于栈中的自动局部变量是危险的,因为函数结束后空间会被释放

修改代码:

方式1:

static char buf[] = "hello"; // 局部静态变量

方式2:

char *buf = malloc(6*sizeof(char)); // malloc 开辟的空间,没释放之前都存在
strcpy(buf, "hello");

fun2中所返回的指针所指向的空间在.rodata中,在整个程序运行的过程中,在.rodata中所开辟空间会一直存在,
所以返回.rodata中的指针是没有问题的,但是空间只能读,不能被修改