【问题标题】:Unusual initialization trouble异常初始化问题
【发布时间】:2012-11-03 18:50:44
【问题描述】:

全部

我正在编写一个非常简单的动态二维数组声明的 C 代码,并使用 memset 对其进行初始化,然后打印出该值。我的代码如下:

float **env;
int i,j,num;

printf("Enter a number : \n");
scanf("%d",&num);

env = (float **)malloc(num*sizeof(float *));

for(i=0;i<num;i++)
{env[i] = (float *)malloc(num*sizeof(float));}

memset(env, 0, sizeof(float)*num*num);

for(i=0;i<num;i++)
{  for (j=0;j<num;j++)
   {
      printf("%f\t",env[i][j]);
      if (j == num -1)
       { printf("\n\n");}
    }
}

for(i=0;i<num;i++)
{free(env[i]);
}

free(env);

当我编译程序时,没有编译错误或警告,但是当我尝试打印出这些值时,我无法打印它们。然后我调试了程序,在memset 语句之后,env 2D 变量显示类似于 CXX0030: Error: expression cannot be evaluated,当我打印值时,会出现一个窗口,显示

Unhandled exception at 0x008b1e27 in ***.exe: 0xC0000005: Access violation reading location 0x00000000.

我尝试使用 2 个 for 循环将 2D 数组 env 显式初始化为 0,它运行良好,我也能够打印值,但是当我使用 memset 时它不起作用。如果有人可以帮助我,那将非常有帮助。谢谢。

【问题讨论】:

    标签: c multidimensional-array initialization


    【解决方案1】:

    首先,通常的建议是:停止使用sizeof 下的类型名称并停止转换malloc 的结果。这才是它应该的样子

    env = malloc(num * sizeof *env);
    
    for (i = 0; i < num; i++)
      env[i] = malloc(num * sizeof *env[i]);
    

    一般来说,更喜欢按照这种模式来编写内存分配

    some_ptr = malloc(N * sizeof *some_ptr);
    

    其次,您使用这种技术创建的“数组”不是经典的 C 风格的连续二维数组。相反,您会得到一个由一堆完全不相关的一维数组组装而成的“模拟”二维数组。后者可能会随机分散在内存中。这立即意味着您将无法将数组作为连续对象处理。与此同时,您的memset 电话试图做到这一点。你不能这样做。在您的情况下,您必须使用循环独立地将每个 1D 子阵列归零。

    但是,您可以将它们全部分配为单个内存块,而不是独立分配一维子数组

    assert(num > 0);
    env = malloc(num * sizeof *env);
    env[0] = malloc(num * num * sizeof *env[0]);
    
    for (i = 1; i < num; ++i)
      env[i] = env[i - 1] + num;
    

    如果如上所示分配,您的数组数据将存储在一个连续的内存块中,尽管您仍然需要了解在使用该数组时您在做什么。例如,memseting 数组数据如下所示

    memset(*env, 0, num * num * sizeof **env);
    

    memset(&env[0][0], 0, num * num * sizeof env[0][0]);
    

    (这是同一件事)。

    【讨论】:

    • 感谢您的建议,我在代码中包含了您提到的内容。所以考虑到你提到的,有没有什么方法可以在不显式使用 2 for 循环的情况下将 2D 数组初始化为 0?
    • @duttasankha:请参阅我回答的第二部分。您的代码不可能。但是如果你按照我的回答改变分配方案,就可以了。
    • 感谢您的帮助。但是,当我停止强制转换 malloc 时,编译器向我抛出类似错误:“void *”类型的值不能分配给“float **”类型的实体错误:“void *”类型的值无法分配给“float *”类型的实体我该怎么办。我正在使用 Microsoft Visual Studio 2010
    • 实际上,当我进行类型转换时,程序运行良好。显式进行类型转换有什么缺点?
    • @duttasankha 这个问题的答案,对于 C 和 C++,已经在 stackoverflow 上讨论死了。例如见stackoverflow.com/questions/1565496/…
    【解决方案2】:

    删除memset 并使用calloc 而不是malloc,它会将分配的内存初始化为零。您现在正在做的是将刚刚分配的指针归零。

    【讨论】:

    • 如果我删除 memset 那么我将如何初始化 2D 数组?
    • 再读一遍,calloc零初始化分配的内存
    【解决方案3】:

    除了迈克尔的回答之外,重要的是要意识到float **env不会为您提供连续的内存块。它会给你一个指向连续内存块的指针,并且在每个内存位置都有一个指向连续内存块的指针,但不能保证这些块是对齐的。

    例如做:

    int *x = malloc(sizeof(int)); 
    int *y = malloc(sizeof(int)); 
    

    x 和 y 不能保证在内存中是连续的,但这是您的代码所假设的。

    【讨论】:

      猜你喜欢
      • 2011-10-18
      • 2011-02-08
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 2020-03-01
      • 1970-01-01
      • 2012-09-07
      相关资源
      最近更新 更多