4

我想在 C 中动态分配(malloc)一个多维字符数组。该数组将具有以下格式:

char *array[3][2] = {
    {"one","two"},
    {"three","four"},
    {"five","six"}
};

在创建数组之前,我已经知道多维数组中所有字符数组的行数和长度。我将如何 malloc 这样的字符数组?

提前致谢!

4

5 回答 5

7

这是分配 char * 的二维数组的一种方法。

之后,您可以分配内容,例如 a[1][2] = "foo"; 请注意,数组的元素被初始化为 (char *)0。

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

char ***alloc_array(int x, int y) {
    char ***a = calloc(x, sizeof(char **));
    for(int i = 0; i != x; i++) {
        a[i] = calloc(y, sizeof(char *));
    }
    return a;
}

int main() {
    char ***a = alloc_array(3, 2);
    a[2][1] = "foo";
    printf("%s\n", a[2][1]);
}

[Charlies-MacBook-Pro:~] crb% cc xx.c
[Charlies-MacBook-Pro:~] crb% a.out
foo
于 2013-09-12T00:53:12.257 回答
2

首先,数组通常以 Row Major 形式存储,因此实际上您有一个向量长度为​​六个元素,每个条目是一个char *ptr。即按行、列标记的元素类似于:

 char *r1c1, *r1c2, *r2c1, *r2c2, *r3c1, *r3c1;

因此,做一个简单的 malloc:

 char *matrix = malloc(3*2*sizeof(char *));

然后将元素设置为:

 matrix[0] = "one";
 matrix[1] = "two";
 matrix[2] = "three";
 matrix[3] = "four";
 matrix[4] = "five";
 matrix[5] = "six";

最后,为了测试这个,编写一个嵌套循环:

 for (int r=0; r<3; r++)
 {
  for (int c=0; c<2; c++);
  {
    printf("%s\n",matrix[r][c]);
  }
 }

请注意,如何首先将矩阵视为向量,然后将其视为矩阵。C无所谓!!

于 2013-09-12T05:44:58.587 回答
1

保持简单,谢尔顿。您选择的答案使用 a char ***,它甚至不接近 a 的等价物char *[2][3]。不同之处在于分配的数量......一个数组只需要一个。

例如,这就是我将如何改造您选择的答案。注意它有多简单?

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

void *alloc_array(size_t x, size_t y) {
    char *(*a)[y] = calloc(x, sizeof *a);
    return a;
}

int main() {
    char *(*a)[2] = alloc_array(3, 2);
    a[2][1] = "foo";
    printf("%s\n", a[2][1]);
}
于 2015-04-25T08:19:30.917 回答
1

char *array[3][2] 只不过是一个二维指针数组。因此,您需要 3*2*sizeof(char *) 的存储空间来存储指针。

正如您所提到的,指针实际上指向以零结尾的字符串,您可能希望字符串也被 malloc'ed。假设所有字符串的总长度为N(包括零终止),则需要的存储空间为(3*2*sizeof(char *) + N)。

为上述大小分配内存并自己复制字符串,如下所示。

在下面的代码中,我们假设列数 (2) 是一个常数

char *(*dst)[2] = (char *(*)[2]) malloc(3*2*sizeof(char *) + N);
char * s = ((char *) dst) + (3*2*sizeof(char *));
for (i = 0; i < 3; i++)
{
    for (j = 0; j < 2; j++)
    {
        strcpy(s, src[i][j]);
        dst[i][j] = s;
        s += strlen(s)+1;
    }
}

注意:在上面的代码中,'dst' 是一个指针,指向 char * 的二维数组的第一行。

如果列数不是恒定的,则语法会发生一些变化,但存储大小是相同的。

char **dst = (char **) malloc(3*2*sizeof(char *) + N);
char * s = ((char *) dst) + (3*2*sizeof(char *));
for (i = 0; i < 3; i++)
{
    for (j = 0; j < 2; j++)
    {
        strcpy(s, src[i][j]);
        dst[i*2 + j] = s; /* 2 is the number of columns */
        s += strlen(s)+1;
    }
}

注意:这里的 'dst' 是指向 char * 的一维数组的第一个元素的指针,并且二维索引是手动完成的。

上面的例子假设字符串长度在分配后不会改变。如果分配后字符串可以随时更改,那么最好为每个字符串单独分配。

于 2013-09-12T03:18:02.163 回答
0

如果您到达此页面,想要创建一个类似的数组int myarray[n][M](这与问题略有不同,因为他们想要一个字符串数组),其中M是固定的并且n可以变化(例如,如果您想要一个坐标数组...... ),那么你可以这样做:

int (*p)[M] = malloc(n*sizeof *p);

然后p[i][j]像以前一样使用。然后,您将获得sizeof p[i] = M*sizeof(int)

#include <stdio.h>
#include <stdlib.h>
#define M 6
int main(int argc, char *argv[])
{
    int n = 4;
    int (*p)[M] = malloc(n*sizeof *p);
    printf("Size of int: %lu\n", sizeof(int));
    printf("n = %d, M = %d\n", n, M);
    printf("Size of p: %lu (=8 because pointer in 64bits = 8 bytes)\n", sizeof p);
    printf("Size of *p: %lu (=M*sizeof(int) because each case is an array of length M)\n", sizeof *p);
    printf("Size of p[0]: %lu (=M*sizeof(int) because each case is an array of length M)\n", sizeof p[0]);
    // Assign
    for (int i=0; i<n; i++) {
        for (int j=0; j<M; j++) {
            (p[i])[j] = i*10+j;
        }
    }
    // Display
    for (int i=0; i<n; i++) {
        for (int j=0; j<M; j++) {
            printf("%2d; ", (p[i])[j]);
        }
        printf("\n");
    }
    return 0;
}

这使:

Size of int: 4
n = 4, M = 6
Size of p: 8 (=8 because pointer in 64bits = 8 bytes)
Size of *p: 24 (=M*sizeof(int) because each case is an array of length M)
Size of p[0]: 24 (=M*sizeof(int) because each case is an array of length M)
 0;  1;  2;  3;  4;  5; 
10; 11; 12; 13; 14; 15; 
20; 21; 22; 23; 24; 25; 
30; 31; 32; 33; 34; 35; 
于 2021-03-31T17:39:29.377 回答