【问题标题】:Seg fault when using structure pointers to access struct members in C使用结构指针访问 C 中的结构成员时出现段错误
【发布时间】:2013-06-14 15:20:56
【问题描述】:

我的程序出了什么问题,当我尝试打印值时出现段错误。

我的目标是在 sample_function 中分配一些值。

在主函数中,我想将结构复制到另一个结构。

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

typedef struct
{
    char        *name;
    char        *class;
    char        *rollno;
} test;

test *
sample_function ()
{
    test *abc;
    abc = (test *)malloc(sizeof(test));

    strcpy(abc->name,"Microsoft");
    abc->class = "MD5";
    abc->rollno = "12345";
printf("%s %s %s\n",abc->name,abc->class,abc->rollno);
return abc;

}

int main(){

test   *digest_abc = NULL;
   test   *abc = NULL;

abc = sample_function();

digest_abc = abc;
printf(" %s  %s  %s \n",digest_abc->name,digest_abc->class,digest_abc->rollno);

return 1;

}

指针一直是我的噩梦,我一直不明白。

【问题讨论】:

  • 你没有为abc分配内存 => 未定义的行为。
  • 您不需要在 C 程序中强制转换 malloc 的返回值。
  • 为什么你只使用 strcpy 作为 name 而不是 class 和 rollno?

标签: c pointers structure


【解决方案1】:
test * sample_function ()
{
    test *abc;

    strcpy(abc->name,"Surya");

您认为abc 在这里指的是什么?答案是,它并没有真正指向任何东西。您需要将其初始化为某种东西,在这种情况下,这意味着分配一些内存。

所以,让我们解决第一个问题:

test * sample_function ()
{
    test *abc = malloc(sizeof(*abc));

    strcpy(abc->name,"Surya");

现在,abc 指向某个东西,我们可以在其中存储东西!

但是……abc-&gt;name 也是一个指针,你认为 那个 指向什么?同样,它并没有真正指向任何东西,你当然不能假设它指向你可以存储你的字符串的地方。

那么,让我们解决您的第二个问题:

test * sample_function ()
{
    test *abc = malloc(sizeof(*abc));

    abc->name = strdup("Surya");
    /* ... the rest is ok ... */
    return abc;
}

现在,还有最后一个问题:您永远不会释放刚刚分配的内存(这在这里可能不是问题,但它会是完整程序中的错误)。

所以,在 main 的末尾,你应该有类似的东西

    free(abc->name);
    free(abc);
    return 1;
}

最后一个问题是一个设计问题:你的结构中有三个指针,只有约定可以帮助你记住哪些是动态分配的(并且必须被释放),哪些指向字符串文字(不能 被释放)。

没关系,只要到处都遵循这个约定。只要您动态分配class 或rollno,就会发生内存泄漏。只要将name 指向字符串文字,就会发生崩溃和/或堆损坏。

正如 japreiss 在评论中指出的那样,执行您的约定的一个好方法是编写专用函数,例如:

void initialize_test(test *obj, const char *name, char *class, char *rollno) {
    obj->name = strdup(name);
    ...
}
void destroy_test(test *obj) {
    free(obj->name);
}
test *malloc_test(const char *name, ...) {
    test *obj = malloc(sizeof(*obj));
    initialize_test(obj, name, ...);
    return test;
}
void free_test(test *obj) {
    destroy_test(obj);
    free(obj);
}

【讨论】:

  • 我已经尝试通过 malloc 分配内存,仍然遇到 seg 错误 - 代码已编辑
  • 恭喜,您在我将其编辑到我的答案中时遇到了第二个错误 :)
  • 解决了,谢谢,最后一个问题,如果我释放分配给 abc 的内存并且仍然想在 digest_abc 中存储值 - 我该怎么做
  • +1 这种对结构的嵌套内存分配很常见,最好将其包装在像void initialize_test(test *the_test, char *name, char *class, char *rollno) 这样的“构造函数”函数中,该函数负责所有的分配和复制,并且void cleanup_test(test *obj) 释放内存。
【解决方案2】:

在您的函数sample_function 中,您返回一个指向abc 的指针。由于 Activation Records 的组织方式,您无法在 C 中执行此操作。

激活记录是一种数据结构,包含函数调用、参数、返回地址、局部变量地址等的所有相关信息......

当您调用一个函数时,一条新的激活记录会被推送到堆栈上,它可能看起来像这样。

// Record for some function f(a, b)
| local variable 1  | <- stack pointer  (abc in your case)
| local variable 2  |
| old stack pointer | <- base pointer
| return address    |   
| parameter 1       |
| parameter 2       |
---------------------
| caller activation | 
|   record          |

当您从一个函数返回时,这条相同的激活记录会弹出堆栈,但是如果您返回旧记录上的变量地址会发生什么?

// popped record
| local variable 1  | <- address of abc   #
| local variable 2  |                     #
| old stack pointer |                     # Unallocated memory, any new function
| return address    |                     # call could overwrite this
| parameter 1       |                     #
| parameter 2       |                     # 
--------------------- <- stack pointer 
| caller activation | 
|   record          |

现在您尝试使用 abc 并且您的程序正确崩溃了,因为它发现您正在访问一个未分配的内存区域。

您也有分配问题,但其他答案已经涵盖了。

【讨论】:

  • 指针test *abc按值返回。 abc 的地址(应该是 test ** 并且确实超出范围)不会出现在我能看到的任何地方。
  • @Useless 我认为这是很常见的术语,但是也可以使用堆栈框架。
  • 我在您回复之前查找并编辑了该评论 - 只是不熟悉:)
  • 嗯,我仍然认为 abc 的地址 是一个红鲱鱼 - 永远不会占用 abc 的地址。
  • @Useless 这不是返回的吗?我只是重新阅读了我写的内容,我的意思是说 pointer 的地址到abc;不是abc 本身
【解决方案3】:

在sample_function 中,您将abc 声明为指向test 结构的指针,但您从不初始化它。它只是指向某处的杂草。然后您尝试取消引用它以存储值 - BOOM。

您的程序根本不需要任何指针;结构可以在 C 中按值传递。

如果您确实想保留与现在类似的接口,您将不得不添加一些动态分配(malloc/free 调用)以确保您的结构实际分配并且您的指针实际上指向它们。

【讨论】:

  • 他也没有为字符串分配任何内存。
  • 是的,这是真的。不过,这只对其中一个很重要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多