【问题标题】:What is the difference between pointer to 2D char array and pointer to 2D int array?指向 2D char 数组的指针和指向 2D int 数组的指针有什么区别?
【发布时间】:2016-12-02 09:01:44
【问题描述】:
    #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("%s\n",p[3]); // statement C  - Seg Fault in this line
        printf("%s\n",p); // working properly displaying "Pointer to"
        printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to"
        printf("%s\n",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 - %d\n",n[10]); // statement D
        printf("nm - %d\n",nm[0][0]);
        return 0;
    }

我的问题:

  1. 请帮我弄清楚 char数组和int数组的情况

  2. 在上面的程序中,我理解当指针指向 char 数组时 指向 char 的 2D 数组,如语句 A 所示 正常显示,但当它被普通字符指针指向时 并尝试在语句 C 中打印字符,它得到了 SegFault, 相反,它应该打印'n'(第一个数组中的第三个数字字符“指针 to") 所以很困惑为什么如果 int 数组我变得正确 语句 D 中的元素 n = 11 以及为什么在这种情况下(语句 C)它 打印不正确。

  3. 如果是 char 数组,数据将如何存储? 如下图所示


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 和 int 数组存储的情况下遇到的问题。

【问题讨论】:

  • char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o','\0'}, {'c','h','a','r', '\0'}, {'p','r','o','g','r','a','m', '\0'}};
  • 语句 D 有效,因为 num 被分配为编译器使用以下公式访问的单个数组:给定语句 num[row][col] 那么它与 *((int *)num + row * 4 + col) 相同。
  • printf("%s\n",p[3]); --> printf("%s\n",&amp;p[3]);
  • 语句 B 与 p = str[0] 相同,因为数组是如何在堆栈上声明的。 p[3] 返回一个字符,而不是 @LPs 所指出的地址。如果要打印p[3],格式说明符应为%c

标签: c arrays pointers multidimensional-array char-pointer


【解决方案1】:

您的段错误是由于您将错误的类型传递给 printf。

编写p[3],您将引用指向矩阵str 第一行的第4 个char 的指针。同*(p+3)

如果你想打印第三个字符,你应该

printf("%c\n",p[3]);

如果要打印第一个 C 字符串(矩阵的第 0 行),您必须:

printf("%s\n",&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("%s\n",p[3]); // statement C  - Seg Fault in this line

关于第3题你要注意正确的存储是:

char str[3][15] = {{'P','o','i','n','t','e','r',' ','t','o','\0'},
                   {'c','h','a','r','\0'},
                   {'p','r','o','g','r','a','m','\0'}};

由于 C-String 是以 null 结尾的,因此,例如,字符串 "Pointer to" 将占用 11 字符


最后一件事是关于int 指针。它运行良好,因为%d 格式说明符需要int 值,而不是地址。所以写:

printf("n - %d\n",n[10]);

完全正确,因为 n[10] 正在取消引用 num 矩阵的第 11 个元素,这意味着第 3 行的第 3 个元素。同*(n+10)

【讨论】:

  • 写 p[3] 你将指针指向第三个字符这是不正确的。
  • 使用p指向内部数组的边界外,如p[10]是未定义的行为。
  • @2501 好的,我编辑了第一条评论。但我不会让你知道第二个。
  • 对不起,我的意思是指针n。它的初始化是错误的,但如果我们忽略它,n 将指向num[0],它的类型是int[4]。访问 n[10] 超出范围。
  • @2501 我猜到了。可能是前几天在海边晒日光浴把我的大脑煮熟了,但我真的不明白你。 num 是一个矩阵 3x4。内存是连续的,所以从&amp;num[0][0]开始有12个ints。所以n[10] 是入站的。我需要咖啡吗? ;)
【解决方案2】:

让我们逐步查看您的代码。

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 的指针(因此你不得不使用强制转换),并且不管str 真的指向存储 'P' 的单元格 - 您应该以更类型安全的方式指向它:

char *p = &str[0][0]; // the same as "p = str[0];"

str[0] 引用了str 的第一个元素,即str[0] 的类型是一个包含15 个char 的数组,那么您可以只引用第一个char 并获取它的地址-@ 987654347@,或者简单地使用“array”类型的表达式衰减为“指向第一个数组元素的指针”这一事实,这就是str[0] 也可以工作的原因。

我们继续

printf("%s\n",p[3]); // statement C  - Seg Fault in this line

这一行会导致未定义的行为,因为格式说明符要求第二个参数是const char *,但您传递的是char。如果你想打印一个字符 - 这样做:

printf("%c\n", p[3]); // prints "n"

然后

    printf("%s\n",p); // working properly displaying "Pointer to"
    printf("%s\n",p+1); // here it is pointing to second element of first array so displaying "ointer to"

这些很好用,因为第二个参数的类型是正确的,而且我们知道字符串是 nul 终止的。

printf("%s\n",pt+1); // printing properly "char" as expected

坦率地说 - 这是不正确的,因为pt + 1 是“指向char 数组的指针”,但您应该传递“指向字符的指针”。应该改写为:

printf("%s\n",*(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 的数组/指向@987654364 的指针@"(感谢衰变)。而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 - %d\n",n[10]); // statement D
printf("nm - %d\n",nm[0][0]);

取消引用是正确的,并且也传递了参数,但请记住,指针初始化不正确。

希望,我已经回答了你所有的问题。

【讨论】:

  • 太棒了。比我的好。 ;)
猜你喜欢
  • 1970-01-01
  • 2020-12-23
  • 2017-09-03
  • 2017-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
相关资源
最近更新 更多