C语言中的双星号和`malloc`

8

我已经学习指针有一段时间了,但似乎无法完全理解它。当你从解释指针的教程跳到实际函数和代码时,似乎有一个没有解释清楚的差距。

让我感到困扰的代码片段如下:

char **output_str = malloc(sizeof(char*));

好的,我的理解如下:
**output_str is a character
*output_str is a pointer to a character
output_str is a pointer to a pointer to a character

据我所知,malloc()返回一个指向刚刚分配的内存起始位置的指针,其大小值等于字符指针(char*)的大小。现在,指向内存起始位置的指针不应该只有一个*吗?如果是这样,我们如何将一个带有*的内容赋给**呢?我很困惑,如果有人能提供一些澄清,并可能对内存部分进行一些深入解释,那就太好了。

4
malloc返回的是void *类型,可以隐式转换为任何其他指针类型。你的陈述意味着malloc分配的空间可以用作存储char *值的空间。 - M.M
我现在认为我已经理解了。回复迟了,抱歉。 - FShiwani
5个回答

4

你的代码块是正确的。使用以下声明:

char **output_str = malloc(sizeof(char*));

output_str是一个指向字符指针的指针,或者它可以被看成是一个字符二维数组,或者是一个字符矩阵。

图形化表示:

Memory Address | Stored Memory Address Value
----------------------------------------------
0              |     .....
1              |     .....
2              |     .....
3              |     .....
4              |     .....
5              |     .....
6              |     .....
.              |     .....
.              |     .....
.              |     .....
n-1            |     .....

假想一下内存(memory)像是一个非常大的数组,你可以通过它的内存地址访问位置。在这种情况下,我们简化地址为自然数。实际上它们是十六进制值。"n"是内存的总大小(或容量)。由于内存从0开始计数,因此大小等同于 n-1。

1. 当你调用:

char **output_str = malloc(sizeof(char*));

操作系统和C编译器会代替我们完成这个过程,但我们可以认为内存已经被改变了。例如,内存地址3现在具有指向指向字符指针的字符指针,名为 output_str

    Memory Address | Name - Stored Memory Address Value (it points to ...)
    -----------------------------------------------------
    0              |     .....
    1              |     .....
    2              |     .....
    3              |     output_str = undefined
    4              |     .....
    5              |     .....
    6              |     .....
    .              |     .....
    .              |     .....
    .              |     .....
    n-1            |     .....

2. 现在如果我们这样说:

*output_str = malloc(sizeof(char));

内存又被改变了。例如,内存地址0现在有一个char指针,名为*output_str

    Memory Address | Name - Stored Memory Address Value (it points to ...)
    -----------------------------------------------------
    0              |     *output_str = undefined
    1              |     .....
    2              |     .....
    3              |     output_str = 0
    4              |     .....
    5              |     .....
    6              |     .....
    .              |     .....
    .              |     .....
    .              |     .....
    n-1            |     .....

3. 声明一个静态实例的字符:

char a = 'a';

因此,我们的内存再次发生了变化,将其放置在 MemoryAddress[6] = 'a':

        Memory Address | Name -> Stored Memory Address Value (it points to ...)
        ------------------------------------------------------
        0              |     *output_str = undefined
        1              |     .....
        2              |     .....
        3              |     output_str = 0
        4              |     .....
        5              |     .....
        6              |     a = 'a' // 'a'is static memory
        .              |     .....
        .              |     .....
        .              |     .....
        n-1            |     .....

最后,我们调用 *output_str = &a;,现在我们告诉字符指针*output_str指向/引用以前实例化的char a

因此,我们最终的内存将如下所示:

            Memory Address | Name - Stored Memory Address Value (it points to ...)
            -----------------------------------------------------
            0              |     *output_str = 6
            1              |     .....
            2              |     .....
            3              |     output_str = 0
            4              |     .....
            5              |     .....
            6              |     a = 'a' // 'a'is static memory
            .              |     .....
            n-1            |     .....

更多信息

 Now printf("Value: " + a) will output "Value: a" 
 printf("Value: " + *output_str[0]) will also output "Value: a" 
 And printf("Value: " + **output_str) will output "Value: a" 

非常感谢您提供如此详细的回复! - FShiwani
没问题!很高兴能帮忙 :) - Santiago Varela

2
那是一个真正的疑问。我会尽力让您清楚明白。 从您问题的细节中,我假设(读作“非常确定”)您理解了malloc分配内存和相应的返回类型。
您有一个疑问,即如果malloc返回指针(void *),如何将其转换为指向指针的指针(char **)。
  1. char **output_str等同于char *(*output_str),这意味着*output_str是指向某些char数据的指针。所以,这就是malloc返回给它的内容。
  2. 再次看到malloc返回指针。但本质上,您已经为指向char的指针(char *)分配了内存,这意味着malloc“字面上”返回指针(void *)到内存,其中您具有char*,这使它成为指向指针的指针char**。

啊!这正是我最初想的。因为我将 char 类型的指针传递给 malloc,它会返回一个指向 char 指针的指针,这就是 output_str 的输出结果。 - FShiwani
如果您喜欢这个答案,请点击接受 :) - Abhineet

0

malloc() 返回 void *,可以隐式转换为任何其他指针类型。在您的情况下,由 malloc() 分配的空间可以用作 char * 值的存储空间。请参考以下示例

char str[10]= {'a'};
//char c = 'c';
char **output_str = malloc(sizeof(char*));

*output_str = str; /* Stored address of a char array of size 10*/

//*output_str = &c; // Stored address of a char, its also correct

printf("%c\n",**output_str); /* Will print the char element, if you are using string address it will print first element,
to print other elements in str use (*output_str)[index] */

0

理解malloc的简单方法:

malloc(sizeof(每个元素) * 元素数量)返回一个新缓冲区的地址(也称为指针)。在这个缓冲区中,每个元素的大小都相同:sizeof(每个元素),并且有元素数量个元素。

例如:

malloc(sizeof(char))返回一个char类型的指针。

malloc(sizeof(char) * 3)返回一个char类型的指针,它是包含3个字符的char数组的第一个元素。

malloc(sizeof(char *) * 6)返回一个char指针类型的指针,它是包含6个char指针的char指针数组的第一个元素。

基本上,malloc(sizeof(WHAT))返回WHAT类型的指针。因此,简单地理解:malloc(Sizeof(WHAT))返回(WHAT *)malloc(Sizeof(WHAT *))返回(WHAT **)......以此类推。

请注意,malloc实际上返回一个(void *)指针。(void *)指针可以稍后转换为任何类型的指针。因此,对于VisualStudio用户有一种很好的方法: int * pbuff = (int *) malloc(sizeof(int) * 6); malloc函数前的(int *)将“阿米巴指针”(void *)转换为(int *)。

0

将output_char视为指向字符串数组的指针,每个字符串都是指向字符数组的指针。当您执行malloc(sizeof(char*))时,您只提供了长度为1的char指针数组,因此*output_char包含单个未初始化的指针(NULL)。

您应该做的是分配足够的指针,以便可以指向一堆字符串。假设您想存储N个字符串,所有这些字符串都由output_char引用。将其初始化为:

// Allocate an array of N string pointers
char **output_str = malloc(sizeof(char*)*N); 

然后您需要为每个字符串分配存储空间:

// Allocate storage for each of the N strings, assume 80 chars max each
// including the null character required at the end of the string
#define MAX_STRING_SIZE 80
int i;
for(i=0; i<N; i++)
   // Allocate storage for each of the strings, but they
   // still need to have some chars written to this storage
   // for these strings to be anything but null strings ""
   output_str[i] = malloc(MAX_STRING_SIZE*sizeof(char));

每个 C 程序的开头都有一个很好的例子:

int main(int argc, char** argv) { /* your code */ }

每个 C 程序都从这个 main 定义开始。它接受两个参数,一个是通过命令行传递到程序中的字符串数量(包括程序本身的名称),而 argv 是对一个字符串参数数组的引用。

例如,使用以下命令行参数调用 myprog:

   myprog -h "Fred" Jones

在main()函数中传递argcargv参数,使得:

   argc = 4
   argv[0] = "myprog"
   argv[1] = "-h"
   argv[2] = "Fred"
   argv[3] = "Jones"

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