簡體   English   中英

使用結構指針訪問C中的結構成員時出現段錯誤

[英]Seg fault when using structure pointers to access struct members in C

我的程序有什么問題,當我嘗試打印值時出現段錯誤。

我的目標是在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;

}

指針一直是我的噩夢,但我從未理解。

test * sample_function ()
{
    test *abc;

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

您認為abc在這里指向什么? 答案是,它並沒有真正指向任何東西。 您需要將其初始化為某種東西,在這種情況下,這意味着分配一些內存。

因此,讓我們解決第一個問題:

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

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

現在, abc指向某個東西,我們可以在其中存儲東西!

但是... abc->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;
}

最后一個問題是設計問題:結構中有三個指針,只有一個約定可以幫助您記住哪個是動態分配的(必須釋放),哪個指向字符串文字( 必須不能釋放)。

只要在所有地方都遵循此約定,就可以了。 一旦動態分配classrollno ,就會發生內存泄漏。 只要將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);
}

在函數sample_function ,返回指向abc的指針。 由於激活記錄的組織方式,您無法在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,並且程序正確崩潰,因為它會看到您正在訪問未分配的內存區域。

您也有分配方面的問題,但是其他答案已經涵蓋了這一點。

sample_function您將abc聲明為指向test結構的指針,但從未對其進行初始化。 它只是指向某個地方的雜草。 然后嘗試取消引用它以存儲值-BOOM。

您的程序根本不需要任何指針。 可以在C中按值傳遞結構。

如果您確實想保持與現在相似的接口,則必須添加一些動態分配( malloc / free調用),以確保結構已實際分配並且指針實際指向它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM