【问题标题】:Segmentation fault after returning a pointer to a struct返回指向结构的指针后出现分段错误
【发布时间】:2023-03-17 06:27:02
【问题描述】:

有从文件读取并返回结构的程序。

struct ion_bin
{
    int freq;
    long height;
    int amplitude;
};

//Dynamic auto allocating array
typedef struct {
  struct ion_bin *array;
  size_t used;
  size_t size;
} Ionogram;

void freeArray(Ionogram *a); //free memory
void insertArray(Ionogram *a, struct ion_bin element); //realloc memory
void initArray(Ionogram *a, size_t initialSize); //malloc memory

Ionogram* read(int argn, char* argv[])
{
    FILE* stream;
    Ionogram ionogramObj;

    //fill ionogram from file by initArray and insertArray  
    //.....

    return &ionogramObj;
}

int main(int argn, char* argv[])
{
    Ionogram* r = read(argn, argv);

    fprintf(stderr,"Array size: %d Used %d\n",r->size, r->used); //SEGMENTATION FAULT ERROR
    //int second = (*(r->array + 2)).amplitude; //YET SEGMENTATION FAULT ERROR TOO

    //fprintf(stderr, "%d", second);
    return 0;
}

此程序编译成功,但在运行时和调试中通过尝试获取返回结构的字段(在 main 方法中)触发分段错误(SIGSEGV)如何修复此错误?

【问题讨论】:

    标签: c struct return


    【解决方案1】:

    你犯了一个初学者的错误,并返回一个指向局部变量的指针。您必须记住,一旦函数返回,局部变量就会超出范围,然后指向它的指针将变得无效。取消引用这个无效指针会导致未定义的行为

    两种可能的解决方案:

    1. 实际上是按值返回结构,而不是指针。
    2. 使用malloc 为结构分配内存,并返回指向该动态分配内存的指针。

    方法一适用于较小的结构,例如您的结构,但对于较大的结构效率低下,因为必须复制整个结构。 (不过,这是一个副本,而不是深副本。因此,如果结构中有指针,则只会复制指针,而不是它们指向的内容。)

    【讨论】:

    • @BlagovestBuyukliev 是的,但这还有其他缺点(例如可重入性和线程安全)。
    • @BlagovestBuyukliev:这种建议有点像告诉初学者用左脚刹车。当然,如果你渴望 F1,这是一项有用的技能,但我们不要一开始就把事情复杂化。
    • 第三个也是最好的行业事实上的标准解决方案:在调用者中分配结构并传递一个指向它的指针。
    • 谢谢!第一个答案是为我工作!我认为,第二种方式并不适合我的情况,因为我不知道在函数读取返回之前我需要分配多少字节。也许我错了。
    【解决方案2】:

    您正在返回一个指向函数末尾超出范围的变量的指针。

      Ionogram ionogramObj;
      return &ionogramObj;
    

    这是 C 中未定义的行为。

    作为替代方案,malloc 函数中结构的内存并返回指向该结构的指针。不要忘记在某个时候free 指针。

    【讨论】:

      【解决方案3】:

      在您的代码中,ionogramObj 变量是函数 read() 的本地变量。一旦函数执行完毕,ionogramObj 就不存在了,所以本质上返回的地址在调用者(main())中是无效的。

      访问无效地址(指针)调用undefined behaviour。分段错误是 UB 的副作用之一。

      为避免这种情况,您需要返回一个生命周期大于被调用函数的地址。借助指针和动态内存分配,您可以实现这一点。

      查看伪代码

      Ionogram* read(int argn, char* argv[])
      {
          FILE* stream = NULL; 
          Ionogram *ionogramObj = NULL;                 //take a pointer
      
          ionogramObj = malloc(sizeof(*ionogramObj));   //allocate memory dynamically
      
          if (!ionogramObj)                             //don't forget to check for success
            //some error message, return or exit, maybe?
          else
             //do normal operation
          //fill ionogram from file by initArray and insertArray  
          //.....
      
          return ionogramObj;                           //return the pointer
      }
      

      另外,动态分配的内存需要free()d 以避免内存泄漏。使用完返回值后,您可以在调用者 (main()) 中使用返回的指针调用 free()

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-20
        相关资源
        最近更新 更多