给双重指针分配内存?

21

我不太明白如何给一个双指针分配内存。我想读取一个字符串数组并将其存储。

    char **ptr;
    fp = fopen("file.txt","r");
    ptr = (char**)malloc(sizeof(char*)*50);
    for(int i=0; i<20; i++)
    {
       ptr[i] = (char*)malloc(sizeof(char)*50);
       fgets(ptr[i],50,fp);
    }

我不是这样做的,而是分配一大块内存并将字符串存储在其中。

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

那样做会有错吗?如果有,为什么会错?


10
不要称之为“双重指针” - 这会在心理上让你走错路 - 它是一个指向指针的指针。 - anon
在C语言中,不要对malloc()realloc()calloc()的调用结果进行强制类型转换 - 这是不必要的,而且可能掩盖了缺少原型的严重错误。 - mlp
8个回答

17

你的第二个示例是错误的,因为每个内存位置概念上不会存储一个 char*,而是一个 char。如果你稍微改变一下你的思维方式,这可能会有所帮助:

char *x;  // Memory locations pointed to by x contain 'char'
char **y; // Memory locations pointed to by y contain 'char*'

x = (char*)malloc(sizeof(char) * 100);   // 100 'char'
y = (char**)malloc(sizeof(char*) * 100); // 100 'char*'

// below is incorrect:
y = (char**)malloc(sizeof(char) * 50 * 50);
// 2500 'char' not 50 'char*' pointing to 50 'char'

因此,你的第一个循环应该像在C语言中处理字符数组/指针数组那样处理。对于一个字符数组的固定块内存来说是可以的,但是你应该使用单个char*而不是char**,因为你没有任何指针在内存中,只有char

char *x = calloc(50 * 50, sizeof(char));

for (ii = 0; ii < 50; ++ii) {
    // Note that each string is just an OFFSET into the memory block
    // You must be sensitive to this when using these 'strings'
    char *str = &x[ii * 50];
}

1
最后一行不应该是char *str = x+(ii*50)吗? - ivanibash
3
不要强制转换malloc()的结果! - Toby Speight

5
 char **ptr;
    fp = fopen("file.txt","r");
    ptr = (char**)malloc(sizeof(char*)*50);
    for(int i=0; i<50; i++)
    {
       ptr[i] = (char*)malloc(sizeof(char)*50);
       fgets(ptr[i],50,fp);
    }

fclose(fp);

也许是您的打字错误,但是如果您要寻找 50 x 50 的矩阵,您的循环应该是 50 而不是 20。另外,在上面提到的内存分配之后,您可以按照 2D 格式访问缓冲区,即 ptr[i][j]。

2
双指针只是指向另一个指针的指针。因此,您可以像这样分配它:
char *realptr=(char*)malloc(1234);
char **ptr=&realptr;

需要记住指针存储的位置(在这个例子中,双指针指向堆栈上的指针变量,因此在函数返回后无效)。


2
我会给出一个例子,或许能够解决疑惑。
char **str;                              // here its kind a equivalent to char *argv[]
str = (char **)malloc(sizeof(char *)*2)  // here 2 indicates 2 (char*)
str[0]=(char *)malloc(sizeof(char)*10)   // here 10 indicates 10 (char)
str[1]=(char *)malloc(sizeof(char)*10)   // <same as above>

strcpy(str[0],"abcdefghij");   // 10 length character 
strcpy(str[1],"xyzlmnopqr");   // 10 length character

cout<<str[0]<<endl;    // to print the string in case of c++
cout<<str[1]<<endl;    // to print the string in case of c++

or

printf("%s",str[0]);
printf("%s",str[1]);  

//finally most important thing, dont't forget to free the allocated mem
free(str[0]);
free(str[1]);
free(str);

1

记忆更简单的另一种方法

情况-1:

步骤1: char *p;

步骤2: 请按以下方式阅读

char(* p); ==> p是指向字符的指针

现在,您只需要为类型(步骤2)执行不带括号的malloc

即,p = malloc(sizeof(char) * some_len);

情况-2:

步骤1: char **p;

步骤2:

请按以下方式阅读

char*(* p); ==> p是指向char *的指针

现在,您只需要为类型(步骤2)执行不带括号的malloc

即,p = malloc(sizeof(char *) * some_len);

情况-3:

没有人使用这个,但仅为了解释而言

char ***p;

阅读为

char**(* p); ==> p是指向char **的指针(并且对于此,请参见上面的情况-2)

p = malloc(sizeof(char**) * some_len);


0

嗯,这是我的做法:

#include <stdlib.h>

int main(void)
{
    int i = -1; // just a counter
    int j = 5; // how many strings
    char *s[j];
    while(++i < j)
        s[i] = malloc(sizeof(char*)); // allocating avery string separately
    return (0);
}

这个也可以工作:

char **allocate(int lines)
{
    int i = -1;
    char **s = malloc(sizeof(char *) * lines); // allocating lines
    while (++i < lines)
    {
        s[i] = malloc(sizeof(char*)); // alicating line
        scanf("%s", s[i]);
    }
    return (s);
}

int main(int ac, char *av[])
{
    int lines = 5; // how many lines
    char **s = allocate(lines);
    return (0);
}

0

补充Pent的答案,正如他所指出的那样,一旦函数返回,您将无法再使用这个双指针,因为它将指向堆栈上函数激活记录中的一个已过时的内存位置。如果您想在函数返回后继续使用这个双指针,可以这样做:

char * realptr = (char *) malloc(1234);
char ** ptr = (char **) malloc(sizeof(char *));
*ptr = realptr;
return ptr;

函数的返回类型显然必须是char **

-5

双指针,简单来说,是指向指针的指针, 在许多情况下,它被用作其他类型的数组。

例如,如果您想创建一个字符串数组,可以简单地执行以下操作:

char** stringArray = calloc(10, 40);

这将创建一个大小为10的数组,每个元素都是长度为40的字符串。

因此,您可以通过stringArray [5]访问它,并获取第6个位置的字符串。

这是其中一种用法,其他用法如上所述,是指向指针的指针,并且可以简单地分配:

char* str = (char*)malloc(40);
char** pointerToPointer = &str //Get the address of the str pointer, valid only in the current closure.

在这里阅读更多信息: 好的数组教程


不,这将创建一个包含100个char的单一数组,假设char占用4个字节。 - Hans Passant
汉斯所说的是正确的。更重要的是,100个char数组被初始化为0(因为您使用了calloc),因此所有这些char都指向null,访问该数组位置将导致错误。 - A. Levy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接