c指针解释通缉

时间:2011-10-23 16:30:24

标签: c pointers

我是关于指针的新手,有人能解释一下下面代码中输出的不同吗?在下面的代码中,我将一些值分配给3d指针。我在任务后打印出来。然后再将它们打印在不同的块中。为什么输出会有所不同?

#include<stdio.h>
#define row 5
#define rw 3
#define col 10

char ***ptr,sh[10];
int i,j,k;

int main()
{
    ptr=(char *)malloc(row*sizeof(char *));

    for(i=0;i<row;i++)
    {
        *(ptr+i)=(char *)malloc(rw*sizeof(char *));
        printf("\t:\n");

        for(j=0;j<rw;j++)
        {
            *(*(ptr+i)+j)=(char *)malloc(col*sizeof(char *));

            if(i==0 && j==0)
            {       
                //  *(*(ptr+row)+rw)="kabul";
                **ptr="zapac";
            }
            else
            {
                sh[0]=i+48;
                sh[1]=',';
                sh[2]=j+48;
                sh[3]='\0';
                *(*(ptr+i)+j)=sh;
            }

            printf("\t%d%d = %s\n",i,j,ptr[i][j]);
        }
        printf("\n");
    }

    for(i=0;i<row;i++)
    {
        for(j=0;j<rw;j++)
        {
            printf("\t%d%d %s\n",i,j,ptr[i][j]);
        }
        printf("\n");
    }
    return 0;
}

输出结果为:

    :
    00 = zapac
    01 = 0,1
    02 = 0,2

    :
    10 = 1,0
    11 = 1,1
    12 = 1,2

    :
    20 = 2,0
    21 = 2,1
    22 = 2,2

    :
    30 = 3,0
    31 = 3,1
    32 = 3,2

    :
    40 = 4,0
    41 = 4,1
    42 = 4,2

我的问题是,为什么以下输出不同意上述内容?

    00 zapac
    01 4,2
    02 4,2

    10 4,2
    11 4,2
    12 4,2

    20 4,2
    21 4,2
    22 4,2

    30 4,2
    31 4,2
    32 4,2

    40 4,2
    41 4,2
    42 4,2

3 个答案:

答案 0 :(得分:0)

因为 sh [10] 是全局定义的,而第一个循环是打印此数组的当前值 - 不保留此数组的内容 - 每次迭代都会更改。对于第二个循环,您将打印在第一个循环期间(即在最后一次迭代中)写入的最后一个值。

你最好在第一个循环的每次迭代中分配:

       for(j=0;j<rw;j++)
       {
            *(*(ptr+i)+j)=(char *)malloc(col*sizeof(char *));
            char* psh = (char*)malloc(10*sizeof(char));
            if(i==0 && j==0)
            {       
               strcpy(psh, "zapac");
            }
            else
            {
                psh[0]=i+48;
                psh[1]=',';
                psh[2]=j+48;
                psh[3]='\0';
                *(*(ptr+i)+j)=psh;
            }

PS要注意硬编码的10-char大小,可能需要额外的检查/断言。

答案 1 :(得分:0)

您获得输出的原因是您的*(*(ptr+i)+j) = sh将所有char *(除了第一个,您已特别处理过的)设置为相同的值,即sh中数组数据的地址。只有sh的一个副本,其数组数据的一个副本;您的所有char *指向该单个副本。当您稍后打印出这些值时,您只需通过不同的指针一遍又一遍地打印相同的数据副本 - 这样您就可以在上次修改它时将所有内容放入sh而不是设置指针时它在里面是什么。

您可能希望每个char *获取数组的新副本而不是仅指向sh,但如果这是您想要的,则必须自己复制数据。

所以...如果你替换这一行:

*(*(ptr+i)+j)=sh;

有类似的东西:

*(*(ptr+i)+j)=malloc(sizeof(sh));
strcpy( *(*(ptr+i)+j), sh );

ptr[i][j] = calloc(1,sizeof(sh));
strcpy( ptr[i][j], sh );

您将得到您的期望,因为每个char *将指向复制时sh中的字符串的新副本。你需要记住以后将它们与你malloc()编辑的所有内容一起释放。

您的大多数malloc()行也不正确,但由于char *char **char ***可能在您的系统上大小相同,因此无论如何都有效。

ptr=(char *)malloc(row*sizeof(char *));

应该是

ptr = (char ***)malloc(row*sizeof(char **));

因为你正在分配一个char **数组(指向char的指针),这个数组是通过char ***(指向指针指向{{}的指针访问的。 1}} 的)。同样地:

char

应该是

*(ptr+i)=(char *)malloc(rw*sizeof(char *));

*(ptr+i)=(char **)malloc(rw*sizeof(char *));

分配通过ptr[i] = (char **)malloc(rw * sizeof(char *)); (指向<{1}} 的指针)访问的char *(指向char的指针)数组。

char **次调用前的演员阵容实际上是可选的 - char的{​​{1}}结果将被转换为您分配给它的任何指针类型。但是,在这种情况下,使用强制转换应该让编译器警告您类型错误。

答案 2 :(得分:0)

@Dmitri对于你​​所看到的症状的原因是正确的,但你的代码中还有其他问题,有些是严重的,有些则不那么严重。

这是您程序的修改版本。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ROW 5
#define RW 3
#define COL 10

int main(void)
{
    char ***ptr;
    char sh[10];
    ptr = malloc(ROW * sizeof *ptr);

    for (int i = 0; i < ROW; i++)
    {
        ptr[i] = malloc(RW * sizeof *(ptr[i]));
        printf("\t:\n");

        for (int j = 0; j < RW; j++)
        {
            ptr[i][j] = malloc(COL * sizeof *(ptr[i][j]));

            if (i==0 && j==0)
            {       
                //  *(*(ptr+ROW)+RW) = "kabul";
                ptr[i][j] = "zapac";
            }
            else
            {
                sh[0] = '0' + i;
                sh[1] = ',';
                sh[2] = '0' + j;
                sh[3] = '\0';
                // ptr[i][j] = sh;
                strcpy(ptr[i][j], sh);

            }

            // printf("\t%d%d = %s\n", i, j, ptr[i][j]);
            printf("\tptr[%d][%d] = \"%s\"\n", i, j, ptr[i][j]);
        }
        printf("\n");
    }

    for (int i = 0; i < ROW; i++)
    {
        for (int j = 0; j < RW; j++)
        {
            // printf("\t%d%d %s\n", i, j, ptr[i][j]);
            printf("\tptr[%d][%d] = \"%s\"\n", i, j, ptr[i][j]);
        }
        printf("\n");
    }
    return 0;
}

我所做的改变是:

  1. 添加#include <stdlib.h>以获取malloc()的声明。这不是可选的(虽然编译器可能会让你省略它)。如果没有#include <stdlib.h>,则前C99编译器会假设malloc()返回int;这会导致未定义的行为。这意味着可能发生任意不好的事情 - 或者它可能恰好在某些系统上发挥作用。

  2. 按照通常使用全大写字母名称的惯例。

  3. 添加一些空格(我发现它使代码更易读,特别是在每个逗号后面和大多数操作符后面都有空格)。

  4. 将变量设为局部变量而不是全局变量。

  5. 在各自的循环中声明循环控制变量。这是C99特有的功能,但您的编译器可能支持它。 (对于gcc,请使用gcc -std=c99。)

  6. 修复malloc()次调用,以根据指针指向的大小计算大小。

  7. 使用索引运算符而不是显式指针算法。一般来说,x[y]表示*(x+y),因此,例如,*(*(ptr+i)+j)可以简单地写为ptr[i][j]

  8. 使用strcpy()sh中存储的字符串复制到the string pointed to by ptr [i] [j]`中,而不仅仅是复制指针。 (这解决了Dmitri已经找到的问题;你应该接受他的答案,因为他先提到了。)

  9. 修改printf来电产生的输出,以便更容易看到发生了什么。