#include <stdio.h>
int main()
{
char str[3][15] = {"Pointer to","char","program"};
char (*pt)[15] = str; // statement A
char *p = (char *)str; // statement B
printf("%sn",p[3]); // statement C - Seg Fault in this line
printf("%sn",p); // working properly displaying "Pointer to"
printf("%sn",p+1); // here it is pointing to second element of first array so displaying "ointer to"
printf("%sn",pt+1); // printing properly "char" as expected
int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*nm)[3] = num[1];
int *n = num;
printf("n - %dn",n[10]); // statement D
printf("nm - %dn",nm[0][0]);
return 0;
}
我的问题:
请帮助我清楚地了解数据存储机制字符数组和整数数组的大小写
在上面的程序中,我理解当指针指向字符数组时指向字符的 2D 数组,如语句 A 所示,它是显示正确,但当它被普通字符指针指向时并尝试在语句 C 中打印字符,它正在获得 SegFault,相反,它应该打印"n"(第一个数组中的第 3 个数字字符"指针"指针到"(所以有困惑为什么在 int 数组的情况下我得到正确的语句 D 中的元素 n = 11 以及为什么在这种情况下(语句 C(它未正确打印。
在字符数组的情况下,数据将如何存储以如下所示的形式
char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o'},
{'c','h','a','r'},
{'p','r','o','g','r','a','m'}};
如果它像这样存储,那么它应该像语句 D 中显示的整数指针数组一样工作请帮助我指导此问题并澄清我在字符和整数数组存储的情况下遇到的问题。
让我们逐步查看您的代码。
char str[3][15] = {"Pointer to","char","program"};
在这里,您创建了一个由三个数组组成的数组,每个数组包含 15 个char
。并且您正在使用字符串文字初始化每个char
数组。如果文字比数组短 - 最后一个元素用零填充,因此它与
char str[3][15] = {
{'P', 'o', 'i', 'n', 't', 'e', 'r', ' ', 't', 'o', 0, 0, 0, 0, 0},
{'c', 'h', 'a', 'r', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{'p', 'r', 'o', 'g', 'r', 'a', 'm', 0, 0, 0, 0, 0, 0, 0, 0}
};
然后
char (*pt)[15] = str; // statement A
在这里,您将pt
创建为指向十五个char
数组的指针,并使用地址 str[0]
对其进行初始化,即 pt
指向 str
中的第一个char[15]
数组。
下一个
char *p = (char *)str; // statement B
这是不行的。据我所知 - 您正在尝试p
指向str
占用的内存中的第一个char
。表达式 str
具有 char (*)[15]
的类型,即它是指向字符数组的指针,而不是指向char
的指针(因此您被迫使用 cast(,并且不管str
确实指向存储'P'
的单元格这一事实 - 您应该以更类型安全的方式指向它:
char *p = &str[0][0]; // the same as "p = str[0];"
str[0]
引用str
的第一个元素,即str[0]
的类型是一个十五个char
的数组,那么你可以只引用第一个char
并获取它的地址 - &(str[0])[0]
,或者简单地使用类型为"array"的表达式衰减为类型"指向第一个数组元素的指针"的事实, 这就是为什么str[0]
也有效。
让我们继续
printf("%sn",p[3]); // statement C - Seg Fault in this line
此行会导致未定义的行为,因为格式说明符要求第二个参数是const char *
但您传递的是char
。如果要打印一个字符 - 请执行此操作:
printf("%cn", p[3]); // prints "n"
然后
printf("%sn",p); // working properly displaying "Pointer to"
printf("%sn",p+1); // here it is pointing to second element of first array so displaying "ointer to"
这些工作得很好,因为第二个参数的类型是正确的,我们知道字符串是 nul 终止的。
printf("%sn",pt+1); // printing properly "char" as expected
坦率地说 - 这是不正确的,因为pt + 1
是"指向char
数组的指针",但您应该传递"指向字符的指针"。它应该重写为:
printf("%sn",*(pt+1)); // or pt[1]
但它似乎有效,因为无论类型不兼容,两个指针都指向同一位置。
下一节关于int
的。
int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*nm)[3] = num[1];
int *n = num;
这里有两个错误:nm
不应该用num[1]
初始化,因为它们具有不兼容的类型:"指向三个int
数组的指针"与"四个int
数组/指向int
的指针"(由于衰减(。而且n
不能用num
初始化,因为它们也有不兼容的类型。根据我对你想要什么的猜测,它应该以下一步的方式出现:
int num[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int (*nm)[4] = num + 1;
int *n = &num[0][0];
最后一个:
printf("n - %dn",n[10]); // statement D
printf("nm - %dn",nm[0][0]);
取消引用是正确的,传递的参数也是如此,但请记住,指针初始化不正确。
希望,我已经涵盖了你所有的问题。
您的段错误是由于您将错误的类型传递给 printf。
写p[3]
,您将指针引用到矩阵str
第一行的第 4 char
。与*(p+3)
相同
如果要打印第 3 个字符,您应该
printf("%cn",p[3]);
如果要打印第一个 C 字符串(矩阵的第 0 行(,则必须:
printf("%sn",&p[3]);
因为%s
想要一个char *
.
如果你在你的命令中添加,至少对于 gcc,-Wall
选项,编译器会告诉你一个好的和有用的警告:
test.c:8:9: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%sn",p[3]); // statement C - Seg Fault in this line
关于问题 3,您必须注意正确的存储是:
char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o',' '},
{'c','h','a','r',' '},
{'p','r','o','g','r','a','m',' '}};
由于 C 字符串以 null 结尾,因此,例如,字符串"Pointer to"
将占用11
个字符
最后一件事是关于int
指针。它运行良好%d
因为格式说明符想要一个int
值,而不是一个地址。所以写道:
printf("n - %dn",n[10]);
是完全正确的,因为n[10]
正在取消引用num
矩阵的第 11 个元素,即第 3 行的第 3 个元素。与*(n+10)
相同