C语言字符串字面量数组存储机制及代码中wp指针指向问题解析
问题:C语言中字符串字面量数组是如何存储的?
先直接点出你代码里的核心问题:第一个循环的逻辑完全错误,导致指针越界访问了不属于你的字符串字面量的内存区域,这就是你看到奇怪输出的原因。下面一步步拆解细节:
1. 第一个循环的错误分析
你的第一个循环代码是:
char *words[] = {"wehrmarcht", "collectorate", "hello", "hello","precorrection", "hello","wehrmarcht"}; char *wp; // ... for(wp = *words; wp - *words < sizeof(words); wp += strlen(wp) + 1) { printf("wp -> %s\n", wp); }
这里有两个致命错误:
- 错误1:错误假设字符串字面量是连续存储的
words是一个char*类型的数组,每个元素都是指向独立字符串字面量的指针。这些字符串字面量在内存中不是连续排列的——编译器会把它们放在只读数据段的不同位置(就算是相同字面量被合并,依然不会和其他字符串连续)。你用wp += strlen(wp)+1试图跳到下一个字符串,这完全是错误的,因为下一个字符串的地址和当前字符串的末尾没有任何"连续"的关联。 - 错误2:循环条件的逻辑完全不匹配
sizeof(words)得到的是整个指针数组的字节大小(在64位系统下,7个char*就是56字节),而wp - *words是计算两个字符指针之间的字符个数(因为wp和*words都是指向char的指针)。拿字符个数和数组的字节大小做比较,完全没有意义,这导致循环会一直执行直到wp越界,访问到内存里的其他数据(比如后面的代码段、其他变量的内容),所以你才会看到precorrection之后的奇怪输出,甚至把printf的格式字符串%s和分隔线都打出来了。
2. 第二个循环为什么正确
第二个循环是遍历指针数组words的每个索引:
for(int i = 0; i < sizeof(words) / sizeof(char *); i++) { printf("words[%d] -> %s\n", i,words[i]); }
这里sizeof(words)/sizeof(char*)计算出数组的元素个数(7),然后逐个取出words[i]——也就是每个指向字符串字面量的指针,自然能正确打印每个字符串。
3. 字符串字面量的实际存储规则
最后回到你的原始问题,字符串字面量在C中的存储规则:
- 通常被编译器放在只读数据段(比如
.rodata),所以不能修改(修改会导致未定义行为)。 - 编译器通常会做字符串池优化:如果代码中有多个相同的字符串字面量,编译器只会存储一份,所以你的
words[0]和words[6](都是"wehrmarcht")、words[2]/words[3]/words[5](都是"hello")的指针值其实是相同的(你可以用printf("%p", words[i])验证)。不过这是编译器的可选优化,不是C标准强制要求的。
内容的提问来源于stack exchange,提问作者rlongying
相关产品推荐
相关产品推荐

