将值分配给指针结构会产生分段错误

时间:2018-11-03 20:56:39

标签: c pointers struct malloc

我创建了该类型的结构和指针。我使用malloc为它分配了内存,但是当我尝试为它实际分配一些值时(特别是读取整数并从文件中浮点数),这给了我一个分段错误,说“在 somelocation的“ 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 **。

2 个答案:

答案 0 :(得分:1)

根据您的代码,这是必需的:

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];以保持简单性。

答案 1 :(得分:0)

在您的代码中,您仅为结构分配了内存,但是该结构的字段仍在“等待”地址分配。指针只是内存中地址的别名,而且由于操作该地址更易于阅读。

有一些方法可以解决您的问题。我创建了四个不同的函数,并使用了两种不同类型的结构。

  • 具有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类型)。数组和结构字段都已经分配了内存,因为我没有使用字段作为指针,而是使用int / float类型的实例。

在functon second_option()中,我定义了包含天气结构实例的指针。结构字段已经分配了内存,因为在结构内部我没有使用字段作为指针。存在int / float类型的实例。但是我必须为指针分配内存。与前面的示例相比,我没有结构数组,因此必须创建它。因此,我为n结构的weather实例分配内存。就像为几个数据框(包含一些重要信息的容器/结构)创建几个(n)个架子一样。 毕竟,应该通过free(3)函数释放由malloc分配的内存。

在functon third_option()中,我既没有为数组字段又为结构字段定义内存。如您所见,现在我使用了新创建的weatherp类型。在这种情况下,我必须为结构字段和数据框(数组)的“架子”分配内存。因此,我为n结构的weatherp实例分配内存,然后在使用fscanf(3)之前,我分别为每个结构字段分配内存。毕竟,应该使用malloc(3)(每个struct字段,最后是struct实例的容器)释放free(3)分配的内存。

最后一个函数 fourth_option()定义了结构的两元素数组(定义为weather类型),但是结构的字段尚未分配内存。因此,在使用fscanf(3)之前,我分别为每个结构字段分配了内存。毕竟,应该使用malloc(3)释放free(3)分配的内存。

一些其他信息:

声明为int a;struct type name;char tab[10];的变量的每个地址已经在栈上动态分配了内存,并且该函数在函数结束后自动“释放”。手动分配的空间(例如,使用malloc(3))会在堆上分配,直到调用free(3)函数。如今,程序结束后的操作系统内核可以释放手动分配的内存,但是一种很好的做法是消除内存泄漏,这表明您知道自己在做什么。

PS。在测试期间,我将月份的数量从12替换为2,并从stdin而非文件中读取数据。当然,我们应该检查类似函数执行成功的事情(例如,malloc(3)调用之后的指针是否不是NULL)。我只是不想使代码复杂化。