C语言一维字符串数组复制到二维字符数组的错误排查
问题根因
你遇到的段错误、乱码问题,本质是代码同时存在逻辑bug和C语言字符串类型的认知错误:
- 首先你参考的整数版本本身就存在未定义行为:内层循环写的是
for(j=0; j<3;i++),循环变量自增的是外层的i而非j,会导致数组越界访问,你能跑出看似正确的结果纯属巧合,逻辑本身就是错的。 - 第一个触发段错误的字符串版本问题:
char *d[3][3]定义的是3*3规格的字符指针数组,你没有给每个指针分配合法的可写内存空间,就直接调用strcpy往野指针指向的地址写数据,必然触发段错误。- 内层循环同样错把
j++写成了i++,运行时会直接数组越界。 - 源数组
s只初始化了8个元素,下标最大到7,循环到i=2、j=2时会访问s[8]的未初始化野指针。
- 第二个输出乱码的版本问题:
char d[3][3]是3行3列的普通字符数组,总大小只有9字节,根本存不下长度最长为6的orange这类字符串,更别说存9个独立字符串。- 赋值语句
d[j][i] = *s[i]只拷贝了每个源字符串的第一个字符,剩余内存要么是初始化的0要么是随机值,用%s输出时会顺着内存地址一直往后读直到碰到结束符\0,自然输出乱码。 - 下标逻辑完全错误:要把长度为9的一维数组按顺序填充到3*3的二维数组,不能一直用外层循环的
i做源数组下标,需要单独的累加变量跟踪源数组的读取位置。
正确实现
字符串和int类型的核心差异是:int是固定长度的值类型,直接赋值即可;字符串本质是char数组,要么给二维数组的每个元素预留足够存下最长字符串的空间做内容拷贝,要么直接存储字符串常量的首地址(不需要修改字符串内容时用这种方式,更省内存)。
版本1:存储字符串常量指针(无需修改字符串内容时使用,无额外内存拷贝)
#include <stdio.h> int main() { // 目标数组:3*3的字符指针数组,每个元素存储一个字符串的首地址 char *d[3][3]; // 源数组:字符串常量指针数组,补全9个元素避免越界 char *s[9] = {"orange","apple","table","chair","cable","TV", "124","HI", "end"}; int i,j,k=0; // 修正循环自增变量,用k跟踪源数组下标 for(i=0; i<3; i++){ for(j=0; j<3; j++){ d[j][i] = s[k++]; // 直接存储字符串常量地址,不需要调用strcpy } } for(i=0; i<3; i++) { for(j=0; j<3; j++) printf("%-8s ", d[j][i]); printf("\n"); } return 0; }
版本2:拷贝字符串内容(需要后续修改字符串内容时使用)
#include <stdio.h> #include <string.h> int main() { // 目标数组:3*3个字符串,每个字符串预留16字节空间,足够存下最长的源串 char d[3][3][16] = {0}; // 源数组:每个字符串预留8字节存储空间,补全9个元素避免越界 char s[9][8] = {"orange","apple","table","chair","cable","TV", "124","HI", "end"}; int i,j,k=0; for(i=0; i<3; i++){ for(j=0; j<3; j++){ strcpy(d[j][i], s[k++]); // 把源字符串内容拷贝到目标数组预留的空间中 } } for(i=0; i<3; i++) { for(j=0; j<3; j++) printf("%-8s ", d[j][i]); printf("\n"); } return 0; }
两个版本运行后都会输出和预期逻辑一致的3*3矩阵:
orange apple table chair cable TV 124 HI end
如果需要调整矩阵填充顺序,只需要修改目标数组的下标赋值规则即可,核心要注意三点:不要写错循环自增变量、不要访问未分配合法权限的内存、给字符串预留足够的存储空间。
内容的提问来源于stack exchange,提问作者Moodkiller
相关产品推荐
相关产品推荐

