簡體   English   中英

為指針結構賦值會導致分段錯誤

[英]Assigning value to a pointer struct gives a segmentation fault

我創建了一個結構體和一個該類型的指針。 我使用 malloc 為它分配了內存,但是當我嘗試實際為其分配一些值(特別是從文件中讀取整數和浮點數)時,它給了我一個分段錯誤,說“在某個位置沒有可用於“ungetwc() 的”。

以下是有關指針和結構的部分代碼:

typedef struct {
    int *rain;
    float *avgtemp;
    float *avgwind;
} weather;

weather *year = (weather*) malloc(n*sizeof(weather));
if (year == NULL)
{
    return 1;
}

for (i = 0; i!=12; i++)
{
    fscanf(infile, "%i %f %f", (year+i)->rain, (year+i)->avgtemp, (year+i)->avgwind);
}

我想問題可能出在 fscanf 中缺少 & 但當我添加它時,我的 IDE 給了我一個警告,提示 int* 是預期的,但提供了 int**。

根據您的代碼,這是必需的:

typedef struct {
    int *rain;
    float *avgtemp;
    float *avgwind;
} weather;

weather *years = malloc(n * sizeof(weather));
if (year == NULL) {
    return 1;
}

weather *year = years;
for (i = 0; i < n; ++i, ++year) {
    year->rain = malloc(sizeof(int));
    year->avgtemp = malloc(sizeof(float));
    year->avgwind = malloc(sizeof(float));
    fscanf(infile, "%i %f %f",
        year->rain, year->avgtemp, year->avgwind);
}

但是,我真正認為您想要的是不要struct使用指針:

typedef struct {
    int rain;
    float avgtemp;
    float avgwind;
} weather;

weather *years = malloc(n * sizeof(weather));
if (year == NULL) {
    return 1;
}

weather *year = years;
for (i = 0; i < n; ++i, ++year) {
    fscanf(infile, "%i %f %f",
        &year->rain, &year->avgtemp, &year->avgwind);
}

更新:

是的,我剛剛從結構中刪除了指針,它確實解決了我遇到的所有問題。 也許我誤解了我教授所說的。

也許。 第一種方法(即你的版本)有效期為某些更復雜的用例。 例如,如果struct有一個char *用於字符串長度可以任意長的字符串。

第二個版本更慣用,更容易使用。

否則,在你的代碼中的其他地方,當訪問一個元素時,我們會做(例如) int rain = *year->rain; 而不是 [更簡單的] int rain = year->rain;

如果struct成員之一需要是一值(例如)結構用於年度報告,而我們需要(例如)每個月的月降雨量(與一年的累積降雨量相比),則可能沒問題rain [再次] 是int *rain; . 但是,鑒於這一點,由於一年中的月數是固定的,我們可以這樣做: int rain[12]; 保持簡單。

在您的代碼中,您僅為一個結構分配了內存,但該結構的字段仍在“等待”地址分配。 指針只是內存中地址的別名,因此操作該地址更具人類可讀性。

有一些方法可以解決您的問題。 我創建了四個不同的函數,並使用了兩種不同類型的結構。

  • 帶有 int 和 float 指針的結構體;
  • 具有已分配內存的 int 和 float 字段的結構。

代碼

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

typedef struct {
    int rain;
    float avgtemp;
    float avgwind;
} weather;

typedef struct {
    int *rain;
    float *avgtemp;
    float *avgwind;
} weatherp;


/* Obtain amount of items in array (implemented in <sys/params.h> header). */
#define nitems(x)       (sizeof((x)) / sizeof((x)[0]))


/* Ex. 1: Using array of defined size. */
void
first_option()
{
        weather year[2];
        int ii;

        for (ii = 0; ii < nitems(year); ii++) {
                fscanf(stdin, "%d %f %f", &year[ii].rain, &year[ii].avgtemp, &year[ii].avgwind);
        }

        for (ii = 0; ii < nitems(year); ii++) {
                fprintf(stdout, "%d %f %f\n", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
        }    
}

/* Ex. 2: Using malloc(3). */
void
second_option()
{
        const int n = 2;
        weather *year =  (weather *)malloc(n * sizeof(weather));
        int ii;

        for (ii = 0; ii < n; ii++) {
                fscanf(stdin, "%d %f %f", &year[ii].rain, &year[ii].avgtemp, &year[ii].avgwind);
        }

        for (ii = 0; ii < n; ii++) {
                fprintf(stdout, "%d %f %f\n", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
        }

        free(year);
}

/* Ex. 3: Values in struct are pointers. */
void
third_option()
{
        const int n = 2;
        weatherp *year =  (weatherp *) malloc(n * sizeof(weatherp));
        int ii;

        for (ii = 0; ii < n; ii++) {
                year[ii].rain = (int *)malloc(sizeof(int));
                year[ii].avgtemp = (float *)malloc(sizeof(float));
                year[ii].avgwind = (float *)malloc(sizeof(float));

                fscanf(stdin, "%d %f %f", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
        }

        for (ii = 0; ii < n; ii++) {
                fprintf(stdout, "%d %f %f\n", *year[ii].rain, *year[ii].avgtemp, *year[ii].avgwind);
        }

        for (ii = 0; ii < n; ii++) {
                free(year[ii].rain);
                free(year[ii].avgtemp);
                free(year[ii].avgwind);
        }
        free(year);


 }

/* Ex. 4: Using array of defined size but struct fields are pointers. */
void
fourth_option()
{
        weatherp year[2];
        int ii;

        for (ii = 0; ii < nitems(year); ii++) {
                year[ii].rain = (int *)malloc(sizeof(int));
                year[ii].avgtemp = (float *)malloc(sizeof(float));
                year[ii].avgwind = (float *)malloc(sizeof(float));
                fscanf(stdin, "%d %f %f", year[ii].rain, year[ii].avgtemp, year[ii].avgwind);
        }

        for (ii = 0; ii < nitems(year); ii++) {
                fprintf(stdout, "%d %f %f\n", *year[ii].rain, *year[ii].avgtemp, *year[ii].avgwind);
        }

        for (ii = 0; ii < nitems(year); ii++) {
                free(year[ii].rain);
                free(year[ii].avgtemp);
                free(year[ii].avgwind);
        }
}


int
main()
{

        first_option();
        second_option();
        third_option();
        fourth_option();

        return (0);
}

在 functon first_option() 中,我定義了結構的二元素數組(定義為weather類型)。 array 和 struct 字段都已經分配了內存,因為我沒有使用作為指針的字段,而是使用int / float類型的實例。

在 functon second_option() 中,我定義了包含天氣結構實例的指針。 結構字段已經分配了內存,因為在結構內部我沒有使用作為指針的字段。 int / float類型的實例。 但我必須為指針分配內存。 與前面的示例相比,我沒有結構數組,因此我必須創建它。 因此,我為nweather結構實例分配內存。 這就像為多個數據框(包含一些重要信息的容器/結構)創建多個 (n) 架子。 畢竟,malloc 分配的內存應該由free(3)函數釋放。

在 functonthird_option () 中,我沒有為數組和結構字段定義內存。 如您所見,現在我使用了新創建的weatherp類型。 在這種情況下,我必須為結構字段和數據框(數組)的“架子”分配內存。 因此,我為weatherp結構體的n實例分配了內存,然后,在使用fscanf(3)我分別為每個結構體字段分配了內存。 畢竟,由malloc(3)分配的malloc(3)應該通過使用free(3) (每個結構域和最后——結構實例的容器malloc(3)來釋放。

最后一個函數fourth_option()定義了結構的兩元素數組(定義為weather類型),但結構的字段沒有分配內存。 因此,在使用fscanf(3)我分別為每個 struct 字段分配內存。 畢竟, malloc(3)分配的malloc(3)應該使用free(3)釋放。

一些額外的信息:

聲明為int a;變量的每個地址int a; , struct type name; char tab[10]; 已經在堆棧上動態分配了內存,並且該內存在函數結束后自動“釋放”。 手動分配的空間(例如使用malloc(3) )在堆上分配,直到調用free(3)函數。 如今,程序結束后的操作系統內核可以釋放手動分配的內存,但消除內存泄漏是一種很好的做法,它表明您知道自己在做什么。

附注。 在測試期間,我將月數從 12 替換為 2 並從stdin讀取數據,而不是從文件中讀取數據。 當然,我們應該檢查諸如成功執行函數之類的事情(例如,如果malloc(3)調用后的指針不是NULL )。 我只是不想使代碼復雜化。

暫無
暫無

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

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