【问题标题】:Segmentation Fault when retrieving value from pointer in another function从另一个函数中的指针检索值时出现分段错误
【发布时间】:2015-11-14 22:52:20
【问题描述】:

我是 C 初学者,遇到以下问题:

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

void myFunc(char **data);

int main() {
    char **header;
    myFunc(header);
    printf("[In main] %s\n", header[1]); // This gives segmentation fault
    return 0;
}

void myFunc(char **data) {
    data = (char **)malloc(2 * sizeof(char *));
    data[0] = "test";
    data[1] = "test 2";
    printf("[In myFunc] %s\n", data[1]); // This works just fine
}

我可以在为它分配内存的函数中检索并打印指针的值,但在此之外(在 main 中),它会出现分段错误。

【问题讨论】:

  • 使其编译干净更改:char **header; to `char **header = NULL;
  • 在 C 中,调用 malloc() 时,1) 不要转换返回值,因为它是 void*,因此可以分配给任何其他指针。强制转换只会使代码混乱,并给代码的调试和维护增加麻烦。 2) 在使用返回值之前,一定要检查 (!=NULL) 以确保操作成功。
  • 这种行:data[0] = "test";需要是:(*data)[0] = "test"; 这行:myFunc(header);传递header的内容需要传递的是header的地址:myFunc( &amp;header );
  • 这一行:data = (char **)malloc(2 * sizeof(char *)); 没有将header 的内容设置为指向 malloc 的区域。它应该是:*data = malloc(2 * sizeof(char *)); 当然,在实际使用指针之前检查 *data 是否为 !=NULL

标签: c pointers


【解决方案1】:

您遇到的问题对于您使用指针以及将指针作为 参数 传递给函数时发生的情况更为基本。当您将指针传递给函数(就像任何变量一样)时,函数会收到该指针(或变量)的副本。这意味着当header 传递给myFunc 时,myFunc 会收到header 作为data 的副本(具有自己的,非常不同的地址):

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

void myFunc(char **data);

int main() {
    char **header;
    printf ("\n the address of header in main: %p\n", &header);
    myFunc(header);
    printf("[In main] %s\n", header[1]); // This gives segmentation fault
    return 0;
}

void myFunc(char **data) {
    data = malloc(2 * sizeof(char *));
    printf ("\n the address of data in myFunc: %p\n", &data);
    data[0] = "test";
    data[1] = "test 2";
    printf("[In myFunc] %s\n", data[1]); // This works just fine
}

输出

$ ./bin/myFunc1

 the address of header in main: 0x7ffd112e27b8

 the address of data in myFunc: 0x7ffd112e2798
[In myFunc] test 2
Segmentation fault

注意:mainheader的地址如何是0x7ffd112e27b8,但是当你在myFunc中为data分配内存时,你是在为myFunc分配起始地址指向0x7ffd112e2798 的指针的新内存块。 main 中的任何内容都不知道内存地址 0x7ffd112e2798

我们如何解决它?

就像您希望将变量传递给函数,更新该变量并将更改的值反映回调用函数(此处为main)时所做的一样 - 您传递 地址的该变量的函数:

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

void myFunc(char ***data);

int main() {
    char **header;
    printf ("\n the address of header in main: %p\n", &header);
    myFunc(&header);  /* passing address of header to myFunc */
    printf("[In main] %s\n", header[1]);
    return 0;
}

void myFunc(char ***data) {
    *data = malloc(2 * sizeof(char *));
    printf ("\n the address of data in myFunc: %p\n", data);
    (*data)[0] = "test";
    (*data)[1] = "test 2";
    printf("[In myFunc] %s\n", (*data)[1]);
}

现在您已经将header地址传递给myFunc 作为data,当您为*data 分配内存时,您正在分配内存并返回指向相同地址的指针headermain 中的地址。这允许:

输出

$ ./bin/myFunc2

 the address of header in main: 0x7ffdd72b1968

 the address of data in myFunc: 0x7ffdd72b1968
[In myFunc] test 2
[In main] test 2

利用来自myFunc的返回

你也可以返回新内存块的起始地址到main并完成同样的事情,例如:

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

char **myFunc(char **data);

int main() {
    char **header;
    printf ("\n the address of header in main: %p\n", &header);
    header = myFunc(header);
    printf("[In main] %s\n", header[1]); // This works fine too
    return 0;
}

char **myFunc(char **data) {
    data = malloc(2 * sizeof(char *));
    printf ("\n the address of data in myFunc: %p\n", &data);
    data[0] = "test";
    data[1] = "test 2";
    printf("[In myFunc] %s\n", data[1]); // This works just fine
    return data;
}

输出

$ ./bin/myFunc3

 the address of header in main: 0x7ffee22e3298

 the address of data in myFunc: 0x7ffee22e3278
[In myFunc] test 2
[In main] test 2

现在main 通过将返回分配给header 知道myFunc 中分配给data 的地址。

【讨论】:

    【解决方案2】:

    原则上,您需要先分配data,然后再调用一个函数来处理它。你反过来做,通过在函数内部分配data,它在函数本身内部是已知的,但在main 中不知道。

    在这种特殊情况下,您需要:

    • 在调用myFunc() 之前为data 分配内存(在该函数本身内,您不需要为data 分配内存):

    header = (char **)malloc(2 * sizeof(char *));

    myFunc(header);

    • myFunc() 内部,不需要为两个指向 char 的指针分配内存,因为您使用的是字符串文字:

    data[0] = "test";

    但是,可能也可以为单个 char 指针分配内存:

    data[0] = (char *)malloc(15 * sizeof(char));

    这种情况下,你可以通过strcpy或者其他一些方法来设置data[0]data[1]的内容


    或者,所有分配都可以在myFunc() 内完成,但您需要更改原型以返回正确的指针。

    char** myFunc() {
        char **data = (char **)malloc(2 * sizeof(char *));
        data[0] = "test";
        data[1] = "test 2";
        printf("[In myFunc] %s\n", data[1]);
    
        return data;
    }
    
    int main() {
        char **header;
        header = myFunc();
        printf("[In main] %s\n", header[1]);
        return 0;
    }
    

    【讨论】:

    • 谢谢,这已经解决了!澄清一下,一旦我将内存传递给函数,我可以为函数内的数组元素分配更多内存吗?像这样 data[0] = (char *)malloc(15 * sizeof(char));
    • 我认为你需要两级内存分配;在main 中为header 分配内存(这是一个指向char 的指针)。在myFunc 中,您需要为单个字符指针分配。
    • 根本没有理由复制字符串。在上面的例子中使用直接赋值是完全可以的。 OP 代码的问题是缺少更直接的赋值:实际的错误是未能从myFunc 返回值,因此header 从未实际设置。
    • 好吧,我在直接分配的特定点上不好 - 编辑了。除此之外,答案中的内存分配有什么问题吗?您能否发布一个不同的答案以明确您的观点。
    • 是的。无需在myFunc 之外分配内存。您可以从函数返回分配的内存:OP 的错误在于没有返回要分配给header 的值。就这样;你大量过度思考这个问题。
    猜你喜欢
    • 2013-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-18
    • 1970-01-01
    • 2017-12-13
    相关资源
    最近更新 更多