我创建了一个该类型的结构和指针。我使用malloc为它分配了内存,但当我试图实际为它分配一些值时(特别是从文件中读取整数和浮点值),它会给我一个分段错误,说"没有可用的源"ungetwc()在somelocation"。
以下是有关指针和结构的部分代码:
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 %fn", 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 %fn", 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 %fn", *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 %fn", *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);
}
在函数中,我定义了结构的两元素数组(定义为weather
类型)。数组和结构字段都已经分配了内存,因为我使用的字段不是指针,而是int
/float
类型的实例。
在函数中,我定义了一个指针,它将包含天气结构的实例。结构字段已经分配了内存,因为在结构内部我没有使用作为指针的字段。存在int
/float
类型的实例。但我必须为指针分配内存。与前面的例子相比,我没有结构数组,所以我必须创建它。因此,我为weather
结构的n
实例分配内存。这就像为几个数据框(包含一些重要信息的容器/结构)创建几个(n)个架子。毕竟,malloc分配的内存应该由free(3)
函数释放。
在函数中,我没有为数组和结构字段定义内存。正如您所看到的,现在我使用了新创建的weatherp
类型。在这种情况下,我必须为结构字段和数据框(数组)的"工具架"分配内存。因此,我为weatherp
结构的n
实例分配内存,然后,在使用fscanf(3)
之前,我分别为每个结构字段分配内存。毕竟,malloc(3)
分配的内存应该通过使用free(3)
来释放(每个结构字段和末尾——结构实例的容器)。
上一个函数fourth_option()定义了结构的两元素数组(定义为weather
类型),但结构的字段没有分配内存。因此,在使用fscanf(3)
之前,我会分别为每个结构字段分配内存。毕竟,malloc(3)
分配的内存应该通过使用free(3)
来释放。
一些附加信息:
声明为int a;
、struct type name;
或char tab[10];
的变量的每个地址都已经在堆栈上动态分配了内存,并且该内存在函数结束后自动"释放"。在调用free(3)
函数之前,在堆上分配手动分配的空间(例如使用malloc(3)
)。如今,操作系统内核在程序结束后可以释放手动分配的内存,但消除内存泄漏是一种很好的做法,这表明你知道自己在做什么。
PS。在测试期间,我将月数从12替换为2,并从stdin
读取数据,而不是从文件中读取数据。当然,我们应该检查函数执行是否成功(例如,如果malloc(3)
调用后的指针不是NULL
)。我只是不想让代码复杂化。