3
    #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 所示,它可以正确显示,但是当它被普通 char 指针指向并尝试在语句 C 中打印 char 时,它会出现 SegFault ,相反,它应该打印'n'(第一个数组“指针”中的第三个数字字符)所以有混淆为什么如果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 数组存储的情况下遇到的问题。

4

2 回答 2

4

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

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一个指向 15char的数组的指针,并使用 的地址对其进行初始化str[0],即pt指向 的第一个char[15]数组str

下一个

char *p = (char *)str; // statement B

不行。据我所知-您正试图指出占用的内存中p的第一个。表达式的类型为,即它是指向字符数组的指针,而不是指向的指针(因此您被迫使用强制转换),并且不管它真正指向存储单元格的事实 - 你应该指向它以更类型安全的方式:charstrstrchar (*)[15]charstr'P'

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

str[0]是引用的第一个元素str,即类型str[0]是一个十五的数组char,那么你可以只引用第一个char并将它的地址 - &(str[0])[0],或者简单地使用类型为“array”的表达式衰减为类型“pointer to第一个数组的元素”,这就是为什么str[0]也有效。

让我们继续

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

此行会导致未定义的行为,因为格式说明符要求第二个参数是 aconst 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's。

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 - %d\n",n[10]); // statement D
printf("nm - %d\n",nm[0][0]);

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

希望,我已经涵盖了你所有的问题。

于 2016-07-28T08:40:20.900 回答
2

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

p[3]你正在推迟指向charmatrix 第一行第 4 行的指针str。如同*(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 是空终止的,因此,例如,字符串"Pointer to"将占用11字符


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

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

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

于 2016-07-28T06:42:50.020 回答