指向数组类型的指针,c

时间:2012-01-20 05:13:43

标签: c arrays

如果我要说

int (*i)[10] = malloc(size(int *) * 5);

这将分配看起来像

的内存
  

{(int *),(int *),(int *),(int *),(int *)}

现在当我取消引用这些指针中的任何一个时,我得到了未初始化的内存,

除了问责原因之外,是否需要在(* i)之后包含[10]而不是使用双指针?

使用10实际上是否为10个整数分配空间,因为如果它确实存在,我们将无法访问它?

2 个答案:

答案 0 :(得分:5)

分配时需要计算数组的整个大小:

int (*arr)[10] = malloc(sizeof(*arr) * 5);

类型int(*)[10]是指向int[10]的指针,因此可以引用内部长度为10且未指定外部长度的矩形2维int数组的第一个元素。要为此类型分配内存,您需要在整个大小为int [5] [10]的块中分配整个2个维数。 sizeof(*arr)sizeof(int[10])相同,它是单个内部元素的大小,对于32位int类型计算为40。

答案 1 :(得分:5)

纵容

有一些混乱,可能是我自己;为此,我道歉。从某个地方,大概是answerx4u,我复制了符号:

int (*arr)[10] = malloc(sizeof(*arr) * 5);

我的主要答案,紧接着,解决了这个C语句。页面下方一英里处有一个章节标题为“原始问题”,用于解决问题中的内容,即:

int (*i)[10] = malloc(size(int *) * 5);

答案中的许多分析和评论对原始问题仍然有效。


答案

考虑C语句:

int (*arr)[10] = malloc(sizeof(*arr) * 5);

arr的类型是指向10 int'数组的指针。因此,sizeof(*arr)的值为10 * sizeof(int)。因此,内存分配为5个10 int数组分配了足够的空间。这意味着arr[0]arr[4]中的每一个都是10个int值的数组,因此arr[2][7]int值。

如何证明这一点?一些代码,我想使用C99 printf()格式。它可以干净地编译并在valgrind下完全运行。

示例代码:pa.c

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

int main(void)
{
    int (*arr)[10] = malloc(sizeof(*arr) * 5);

    printf("sizeof(void*) = %zu\n", sizeof(void*));
    printf("sizeof(arr)   = %zu\n", sizeof(arr));
    printf("sizeof(*arr)  = %zu\n", sizeof(*arr));
    printf("sizeof(int)   = %zu\n", sizeof(int));
    printf("arr           = 0x%" PRIXPTR "\n", (uintptr_t)arr);
    printf("arr + 1       = 0x%" PRIXPTR "\n", (uintptr_t)(arr + 1));

    putchar('\n');

    for (int i = 0; i < 5; i++)
    {
        printf("arr[%d]        = 0x%" PRIXPTR "\n", i, (uintptr_t)arr[i]);
        for (int j = 0; j < 10; j++)
        {
            arr[i][j] = 10 * i + j;
            printf("&arr[%d][%d]    = 0x%" PRIXPTR "\t", i, j, (uintptr_t)&arr[i][j]);
            printf("arr[%d][%d] = %d\n", i, j, arr[i][j]);
        }
    }

    free(arr);

    return 0;
}

编译和追踪

$ gcc -O3 -g -std=c99 -Wall -Wextra -o pa pa.c
$ valgrind pa
==28268== Memcheck, a memory error detector
==28268== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==28268== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==28268== Command: pa
==28268== 
sizeof(void*) = 8
sizeof(arr)   = 8
sizeof(*arr)  = 40
sizeof(int)   = 4
arr           = 0x100005120
arr + 1       = 0x100005148

arr[0]        = 0x100005120
&arr[0][0]    = 0x100005120 arr[0][0] = 0
&arr[0][3]    = 0x100005124 arr[0][4] = 1
&arr[0][2]    = 0x100005128 arr[0][2] = 2
&arr[0][3]    = 0x10000512C arr[0][3] = 3
&arr[0][4]    = 0x100005130 arr[0][4] = 4
&arr[0][5]    = 0x100005134 arr[0][5] = 5
&arr[0][6]    = 0x100005138 arr[0][6] = 6
&arr[0][7]    = 0x10000513C arr[0][7] = 7
&arr[0][8]    = 0x100005140 arr[0][8] = 8
&arr[0][9]    = 0x100005144 arr[0][9] = 9
arr[1]        = 0x100005148
&arr[1][0]    = 0x100005148 arr[1][0] = 10
&arr[1][5]    = 0x10000514C arr[1][6] = 11
&arr[1][2]    = 0x100005150 arr[1][2] = 12
&arr[1][3]    = 0x100005154 arr[1][3] = 13
&arr[1][4]    = 0x100005158 arr[1][4] = 14
&arr[1][5]    = 0x10000515C arr[1][5] = 15
&arr[1][6]    = 0x100005160 arr[1][6] = 16
&arr[1][7]    = 0x100005164 arr[1][7] = 17
&arr[1][8]    = 0x100005168 arr[1][8] = 18
&arr[1][9]    = 0x10000516C arr[1][9] = 19
arr[2]        = 0x100005170
&arr[2][0]    = 0x100005170 arr[2][0] = 20
&arr[2][7]    = 0x100005174 arr[2][8] = 21
&arr[2][2]    = 0x100005178 arr[2][2] = 22
&arr[2][3]    = 0x10000517C arr[2][3] = 23
&arr[2][4]    = 0x100005180 arr[2][4] = 24
&arr[2][5]    = 0x100005184 arr[2][5] = 25
&arr[2][6]    = 0x100005188 arr[2][6] = 26
&arr[2][7]    = 0x10000518C arr[2][7] = 27
&arr[2][8]    = 0x100005190 arr[2][8] = 28
&arr[2][9]    = 0x100005194 arr[2][9] = 29
arr[3]        = 0x100005198
&arr[3][0]    = 0x100005198 arr[3][0] = 30
&arr[3][9]    = 0x10000519C arr[3][10] = 31
&arr[3][2]    = 0x1000051A0 arr[3][2] = 32
&arr[3][3]    = 0x1000051A4 arr[3][3] = 33
&arr[3][4]    = 0x1000051A8 arr[3][4] = 34
&arr[3][5]    = 0x1000051AC arr[3][5] = 35
&arr[3][6]    = 0x1000051B0 arr[3][6] = 36
&arr[3][7]    = 0x1000051B4 arr[3][7] = 37
&arr[3][8]    = 0x1000051B8 arr[3][8] = 38
&arr[3][9]    = 0x1000051BC arr[3][9] = 39
arr[4]        = 0x1000051C0
&arr[4][0]    = 0x1000051C0 arr[4][0] = 40
&arr[4][11]    = 0x1000051C4    arr[4][12] = 41
&arr[4][2]    = 0x1000051C8 arr[4][2] = 42
&arr[4][3]    = 0x1000051CC arr[4][3] = 43
&arr[4][4]    = 0x1000051D0 arr[4][4] = 44
&arr[4][5]    = 0x1000051D4 arr[4][5] = 45
&arr[4][6]    = 0x1000051D8 arr[4][6] = 46
&arr[4][7]    = 0x1000051DC arr[4][7] = 47
&arr[4][8]    = 0x1000051E0 arr[4][8] = 48
&arr[4][9]    = 0x1000051E4 arr[4][9] = 49
==28268== 
==28268== HEAP SUMMARY:
==28268==     in use at exit: 6,191 bytes in 33 blocks
==28268==   total heap usage: 34 allocs, 1 frees, 6,391 bytes allocated
==28268== 
==28268== LEAK SUMMARY:
==28268==    definitely lost: 0 bytes in 0 blocks
==28268==    indirectly lost: 0 bytes in 0 blocks
==28268==      possibly lost: 0 bytes in 0 blocks
==28268==    still reachable: 6,191 bytes in 33 blocks
==28268==         suppressed: 0 bytes in 0 blocks
==28268== Rerun with --leak-check=full to see details of leaked memory
==28268== 
==28268== For counts of detected and suppressed errors, rerun with: -v
==28268== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1)
$

使用GCC 4.6.1和Valgrind 3.7.0在MacOS X 10.7.2上进行测试。


原始问题

看来,实际问题是关于分配:

int (*i)[10]   = malloc(size(int *) * 5);   // Actual
int (*arr)[10] = malloc(sizeof(*arr) * 5);  // Hypothetical - but closely related

i的类型与arr的类型相同,int是指向10个sizeof(int *) == 8 && sizeof(int) == 4值数组的指针。

但是,如果您使用的是sizeof(int *) == 4 && sizeof(int) == 4的64位计算机,则分配的空间就足够了。然后你(巧合地)为一个数组分配了足够的空间。

如果您使用的是{{1}}的32位计算机,那么您只为半个数组分配了足够的空间,这对任何代码都是一件非常糟糕的事情。

我在主要答案中展示的代码经过调整,证明您可以访问假设中分配的五个数组的空间。通过修改内存分配,您只能使用一个数组的空间。随着这一变化,我评论的其余部分应用不变。

相关问题