Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/64.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C语言中二维数组的动态内存分配_C_Arrays_Dynamic - Fatal编程技术网

C语言中二维数组的动态内存分配

C语言中二维数组的动态内存分配,c,arrays,dynamic,C,Arrays,Dynamic,我正在阅读有关2D阵列的动态内存分配的内容,我正在看以下示例: int nrows = 2; int ncols = 5; char **pvowels = malloc(nrows * sizeof(char)); pvowels[0] = malloc(ncols * sizeof(char)); pvowels[1] = malloc(ncols * sizeof(char)); 我的理解是,第二个和第三个malloc都分配了大小为5个字符的内存,pvowels[0]和pvowels

我正在阅读有关2D阵列的动态内存分配的内容,我正在看以下示例:

int nrows = 2;
int ncols = 5;

char **pvowels = malloc(nrows * sizeof(char));

pvowels[0] = malloc(ncols * sizeof(char));
pvowels[1] = malloc(ncols * sizeof(char));
我的理解是,第二个和第三个malloc都分配了大小为5个字符的内存,pvowels[0]和pvowels[1]分别指向每个字符,但我在理解第一个malloc时遇到了困难


第一个malloc看起来像是分配了2个字符大小的内存,并使用它来存储两个指针。但是一个字符不是只有256个可能的值,指针可以达到数十亿吗?因此,如果它分配内存来存储指针,它不需要比chars大吗?

char**pvowels是指向指针的指针,这意味着它的行为类似于声明如下的数组: char*pvowels[一个数字];
因此,在您提供的示例中,基本上是分配指向char的指针,而不是指针。

char**pvowels是指向指针的指针,这意味着它的行为类似于声明如下的数组: char*pvowels[一个数字]; 因此,在您提供的示例中,基本上是分配了指向字符的指针,而不是指针。

首先,您的第一个malloc是不正确的。使用nrows*sizeofchar只分配2个字节,而您需要2行char*指针。您必须这样分配:

char **pvowels = malloc(nrows * sizeof(char*));
或:

还要注意,char**pvowels不是2D数组,只是指向char指针的指针。如果您使用的是2D数组,例如char pvowels[]],则不需要在堆上动态分配指针。您也可以使用2D数组来解决您的问题,例如char pvowels[2][5],因为在这种情况下,NCOL和nrows似乎是固定的

其次,您对pvowels[0]和pvowels[1]的分配将只为4个有效字符(如abcd)留出空间,因为空终止字符\0需要1个空间。你应该写:

pvowels[0] = malloc(ncols+1); /* +1 for '\0' */
pvowels[1] = malloc(ncols+1);
注意:sizeofchar始终为1,因此不需要包含它。您还应该检查malloc是否返回NULL

首先,您的第一个malloc不正确。使用nrows*sizeofchar只分配2个字节,而您需要2行char*指针。您必须这样分配:

char **pvowels = malloc(nrows * sizeof(char*));
或:

还要注意,char**pvowels不是2D数组,只是指向char指针的指针。如果您使用的是2D数组,例如char pvowels[]],则不需要在堆上动态分配指针。您也可以使用2D数组来解决您的问题,例如char pvowels[2][5],因为在这种情况下,NCOL和nrows似乎是固定的

其次,您对pvowels[0]和pvowels[1]的分配将只为4个有效字符(如abcd)留出空间,因为空终止字符\0需要1个空间。你应该写:

pvowels[0] = malloc(ncols+1); /* +1 for '\0' */
pvowels[1] = malloc(ncols+1);

注意:sizeofchar始终为1,因此不需要包含它。您还应该检查malloc是否返回NULL

分配到char的nrows指针数组,然后分别分配到ncols char的nrows数组有一个缺点,即单独的内存分配不能保证在内存中是连续的。这种碎片可能会导致性能下降

更好的方法是分配足够的内存来保存2d数组,并将生成的指针分配给指向ncols字符数组的指针。如图所示,这种方法确实依赖于VLA,但自C99以来,VLA一直是C的一部分。这样做的优点是一次分配内存,只需分配一个空闲内存

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

int main(void)
{
    size_t nrows = 2;
    size_t ncols = 5;

    /* Allocate space for a 2d array */
    char (*pvowels)[ncols] = malloc(sizeof (char[nrows][ncols]));

    /* Another alternative */
//    char (*pvowels)[ncols] = malloc(nrows * ncols);

    if (pvowels == NULL) {
        fprintf(stderr, "Unable to allocate memory\n");
        exit(EXIT_FAILURE);
    }

    for (size_t i = 0; i < nrows; i++) {
        for (size_t j = 0; j < ncols; j++) {
            pvowels[i][j] = 'a' + i * ncols + j;
        }
    }

    for (size_t i = 0; i < nrows; i++) {
        for (size_t j = 0; j < ncols; j++) {
            printf("%5c", pvowels[i][j]);
        }
        putchar('\n');
    }

    free(pvowels);

    return 0;
}

分配到char的nrows指针数组,然后分别分配到ncols char的nrows数组有一个缺点,即单独的内存分配不能保证在内存中是连续的。这种碎片可能会导致性能下降

更好的方法是分配足够的内存来保存2d数组,并将生成的指针分配给指向ncols字符数组的指针。如图所示,这种方法确实依赖于VLA,但自C99以来,VLA一直是C的一部分。这样做的优点是一次分配内存,只需分配一个空闲内存

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

int main(void)
{
    size_t nrows = 2;
    size_t ncols = 5;

    /* Allocate space for a 2d array */
    char (*pvowels)[ncols] = malloc(sizeof (char[nrows][ncols]));

    /* Another alternative */
//    char (*pvowels)[ncols] = malloc(nrows * ncols);

    if (pvowels == NULL) {
        fprintf(stderr, "Unable to allocate memory\n");
        exit(EXIT_FAILURE);
    }

    for (size_t i = 0; i < nrows; i++) {
        for (size_t j = 0; j < ncols; j++) {
            pvowels[i][j] = 'a' + i * ncols + j;
        }
    }

    for (size_t i = 0; i < nrows; i++) {
        for (size_t j = 0; j < ncols; j++) {
            printf("%5c", pvowels[i][j]);
        }
        putchar('\n');
    }

    free(pvowels);

    return 0;
}

一个简单易懂的代码:只使用一个指针来存储和访问

#include<stdio.h>
#include<stdlib.h>
int main(){
    int *a,n,r,c,i,j;
    scanf("%d",&n);
    r=c=n;
    a=(int *)malloc(r*c*sizeof(int));
    for(i=0;i<r;i++)
    {
        for(j=0;j<c;j++){
            scanf("%d",(a+i*c+j));
        }
    }
    for(i=0;i<r;i++)
    {
        for(j=0;j<c;j++){
            printf("%d",*(a+i*c+j));
        }
    }
}

参考文献:geeksforgeks.org

一段简单易懂的代码:只需使用一个指针即可存储和访问

#include<stdio.h>
#include<stdlib.h>
int main(){
    int *a,n,r,c,i,j;
    scanf("%d",&n);
    r=c=n;
    a=(int *)malloc(r*c*sizeof(int));
    for(i=0;i<r;i++)
    {
        for(j=0;j<c;j++){
            scanf("%d",(a+i*c+j));
        }
    }
    for(i=0;i<r;i++)
    {
        for(j=0;j<c;j++){
            printf("%d",*(a+i*c+j));
        }
    }
}

参考文献:geeksforgeks.org

第一个malloc是错误的。char**pvowels是指向字符指针的指针。如果需要两行字符,则需要两个指针。您只分配了两个字节,nrows*sizeofchar。你需要两个指针的空间,nrows*sizeofchar*。当前的代码可能会导致访问冲突。第一个malloc的可能副本是错误的。char**pvowels是指向字符指针的指针。如果需要两行字符,则需要两个指针。您只分配了两个字节,nrows*sizeofchar。你需要两个指针的空间,nrows*sizeofchar*。你现有的代码可能会导致访问冲突。可能是重复的我想你已经回答了OP的问题,
但有一点值得商榷:我认为OP说第二个和第三个malloc都分配了5个字符大小的内存是正确的。毕竟,\0只是另一个字符,我看不出OP在这里意味着为长度为5的字符串分配内存。YMMV@DavidBowling对,我将编辑我的答案:。这可能是一个错误的观察,但无论如何,向char*分配添加+1始终是一个好习惯;我只是想建议OP在评估中是正确的,即后两次分配每个分配5个字符的空间+1我认为您已经回答了OP的大部分问题,但有一个疑问:我认为OP说第二个和第三个malloc都分配了5个字符大小的内存是正确的。毕竟,\0只是另一个字符,我看不出OP在这里意味着为长度为5的字符串分配内存。YMMV@DavidBowling对,我将编辑我的答案:。这可能是一个错误的观察,但无论如何,向char*分配添加+1始终是一个好习惯;我只是想建议OP在评估中是正确的,即后两次分配每个分配5个字符的空间+1+1对于使用char*pvowels[ncols],这是一个非常好的方法。使用size_t而不是int也很好,因为malloc需要size_t.+1来使用char*pvowels[ncols],这是一种非常好的方法。使用size\u t而不是int也很好,因为malloc需要size\u t。