深入探究 C 字符串

平时处理 C 和 C++ 字符串的时候有下面几个问题困扰着我:

  1. C 的字符串与普通数组有什么不同?
  2. C 中字符串字面量为什么是 const char * ?字符串字面量的赋值操作需要拷贝吗?

在这篇文章中我想简单解答一下上面的问题。如果你跟我一样有同样的疑惑,请继续看下去。

C 字符串与普通数组比较

字符串可以理解为一串字符,直观上可以将它用字符数组存储,在 C 中也不例外。与普通数组不同的是,C 支持下面的字面量初始化方式:

char[] str = "C and C++ Strings";
const char* = "C and C++ Strings"; // 指针类型

而普通数组的字面量初始化方式是:

int nums[] = {1, 2, 3, 4, 5};
int nums[5] = {5, 6, 7, 8, 9};
int *nums_ptr = nums; // 指针类型
// 在 C 和 C++ 中指针和数组类型可以相互赋值

我们在处理数组时总是需要知道它的长度。
如果直接处理数组类型,长度计算可以很容易地通过 sizeof 获取。但是如果处理的是指针类型,就无法通过 sizeof 获取——指针类型长度恒定(32 位机器长度为 4,64 位机器长度为 8)。
针对指针类型长度的获取,一种方法是临时变量存储并通过参数传递。而 C 提供了另一种方式,也就是在字符串数组后加一个特殊的终止符 ‘\0’,这样就可以通过遍历指针后续地址来确定指针所指字符串的长度——时间复杂度 O(N)。有了终止符我们就不再需要在处理字符串的指针时,额外传递长度参数。

总结一下,C 字符串是一个以终止符 ‘\0’ 结尾的特殊字符数组。所以,我们也可以通过下面的方式来初始化字符串:

char str[] = {'C', 'i', 'a', 'o', '.', 'Y', 'o', 'u', 'n', 'g', '\0'}; 
char str[11] = {'C', 'i', 'a', 'o', '.', 'Y', 'o', 'u', 'n', 'g', '\0'}; // 注意最后的终止符

C 字符串字面量的赋值

目前我们提到的字符串初始化方式包括:

// 字符串字面量
char[] str = "C and C++ Strings"; // 字符数组
const char* str = "C and C++ Strings"; // 指针类型
// 字符数组
char str[] = {'C', 'i', 'a', 'o', '.', 'Y', 'o', 'u', 'n', 'g', '\0'}; 

上述两种字符串初始化方式,因为可读性远远好于字符数组的缘故,字符串字面量初始化字符串被大多数语言使用。那么 C 中两种字符串字面量初始化方式有什么异同?
有一个大前提,在 C 和 C++ 中字符串字面量是只读数据,存放在 .rodata 段内。这部分涉及到编译链接的内容,有兴趣的读者可以找资料了解一下 。我们可以通过指针引用这部分内存,又因为是只读数据,为避免修改,需要使用 const char *(指向常量的指针),从编译层面施加限制。甚至如果使用普通指针引用,编译器会提示告警:

char* str = "C and C++ Strings"; // 普通指针类型
// warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]

因为是指针,所以就不存在内存拷贝操作。这对应于上面字符串字面量的第二种初始化方式。而第一种字符数组初始化不同,为了保证数组可修改的特性,只好把存放在 .rodata 段内的字符串字面量拷贝到数组的内存中。代价就是多了一步拷贝操作。

思考问题

  1. 指向常量的指针和常量指针有什么区别?
  2. 如果强制修改字符串字面量会发生什么?

参考资料

  1. 程序员的自我修养——链接、装载与库,俞甲子 石凡 潘爱民 著
  2. C-Strings in C++ http://clarkkromenaker.com/post/cpp-cstrings/
  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值