【问题标题】:Allocate memory in one function and use it in another function在一个函数中分配内存并在另一个函数中使用它
【发布时间】:2016-10-20 00:46:39
【问题描述】:

以下代码似乎有效。 linux 上的 gcc 5.2.1 没有给出任何警告。

我是 C 的新手。我通过用英语句子和反复试验写下 & 和 * 运算符在每一行的作用来完成这项工作。

有两件事我不确定。

A 行中p0 的初始值是不可预测的。然而,E 行给 main 中变量 p0 的值指定的地址赋值。这会导致任何问题吗?如果是这样,如何解决?

代码使用了这么多*,比如C行中的***。它可以使用更少的*而不得到gcc的警告吗?

谢谢。

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

void* f(int*** ptr_p)     //C
{
    int** p = *(ptr_p);   //D
    *p      = malloc(8);  //E
    *(*p)   = 200;        //F
    (*p)[1] = 4;          //G
}

int main(void)
{
    int** p0;             //A
    f(&p0);               //B
    printf("%d, %d\n",*(*p0), (*p0)[1]);
    free(*p0);            //H
}

如果你想看英文句子,就在这里。

警告:我是 C 的新手,我不知道他们是否都正确。

线 [A] int** p0;

p0 的值是不可预测的。

行 [B] f(&amp;p0);

&amp;p0 是变量p0 的地址。 f(&amp;p0) 表示调用函数f 并将&amp;p0 分配给函数的第一个参数。

行 [C] void* f(int*** ptr_p)

B 行将&amp;p0 分配给ptr_p。这意味着ptr_p 的值现在等于主函数中变量p0 的地址。

行 [D] int** p = *(ptr_p);

*(ptr_p) 表示由ptr_p 的值指定的地址处的值,解释为地址。 ptr_p的值是主函数中变量p0的地址,如C行所述。所以,*(ptr_p)是主函数中变量p0的值。

p = *(ptr_p); 表示将主函数中p0 的值赋给p 的值

行 [E] *(p) = malloc(8);

*(p) 表示由p 的值指定的地址处的值。 p 的值是 main 中 p0 变量的值,如 [D] 行中所述。那么*(p)表示main()p0变量的值所指定的地址值。

malloc(8)在内存中保留8个字节,并返回8个字节中第一个字节的地址。

整行的意思是将这8个字节的第一个字节的地址赋值为main()中的p0变量指定的地址的值。

行 [F] *(*p) = 200;

行 [G] (*p)[1] = 4;

(p)[1] 表示*(p + 1)

(*p)[1] 表示*(*p + 1)

【问题讨论】:

  • 现在是凌晨 3 点 10 分,我现在去睡觉。明天会检查答案。这看起来很有趣也很有用。提前致谢。

标签: c reference dereference


【解决方案1】:

是的,E 行是个问题。实际上,您已经在 D 行遇到了麻烦,因为您读取了p0 的(未定义)值。这在 C 中是被禁止的;这是可怕的未定义行为的一部分,这意味着所有的赌注都被取消了,编译器被合法地允许输出它想要的任何东西:一个崩溃的二进制文件,或者打印“Hello world!”,你的名字它。

您正确地看到p0 应该指向int * 缓冲区,然后才能写入该缓冲区。但是,不需要这种额外的间接级别。 p0 可以是int *

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

void f(int** ptr_p)     //C
{
    *ptr_p      = malloc(sizeof(int) * 2);  //E
    (*ptr_p)[0] = 200;        //F
    (*ptr_p)[1] = 4;          //G
}

int main(void)
{
    int* p0;             //A
    f(&p0);              //B
    printf("%d, %d\n", p0[0], p0[1]);
    free(p0);            //H
    return 0;
}

最后一件事:malloc 可能会失败并返回 NULL;一个强大的程序会检查这一点。

【讨论】:

  • 最后,我选择了你的方法,因为我试图从函数返回(指向)多个数组。本题用到的代码(stackoverflow.com/questions/37933956/…)谢谢。
  • @rxu 我只选择这种风格是为了与您的原始代码保持一致。当只有一件事要返回时,我通常使用返回值;即使有两三个,我有时也会把它们打包成一个结构,然后再返回。优化编译器可以生成极其高效的代码,特别是如果函数是 static(编译单元本地,因此不受任何 ABI 约束)。一般来说,不获取局部变量的地址有助于编译器“将其从内存中拉出”,即将它保存在 CPU 寄存器中。
  • 啊。下次我会使用结构。
【解决方案2】:

你需要更多的星星:越少越好,所以我简化了你的程序。

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

int *f(int size)                    // returns a pointer
{
    int *p;                         // define a pointer
    p = malloc(size);               // allocate memory to it
    if(p == NULL) {                 // check the result
        exit(1);                    // emergency exit
    }
    *p = 200;                       // put a value at p[0];
    p[1] = 4;                       // put a value at p[1];
    return p;                       // return the pointer
}

int main(void)
{
    int *p0;                        // pointer as yet has no value assigned
    p0 = f(2 * sizeof *p0);         // get memory for 2 ints and initialise it
    printf("%d, %d\n", *p0, p0[1]); // show the two ints assigned
    free(p0);                       // release the memory
    return 0;                       // end of program
}

程序输出:

200, 4

除了更少的星星之外,您的程序还有两个主要变化

  1. 函数直接返回一个指针。通过参数设置它需要多一颗星。

  2. 请求的内存量用于数据类型的两个元素,而不是“硬编码”。

此外,您认为基于指针访问数组的方法不止一种是正确的。

【讨论】:

  • 阿门,三星级功能一般不是对功能的恭维(虽然有时是必要的)
  • 感谢您非常清晰和干净的实施。 cmets 非常有帮助。下次我只需要从函数中返回(指向)一个数组时,我将使用它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多