【问题标题】:C - Build dynamically allocated array of pointers to structures filled with input from fileC - 构建动态分配的指针数组,指向填充来自文件的输入的结构
【发布时间】:2012-04-22 00:08:59
【问题描述】:

我需要构建一个指向动态分配结构 (DBrecord) 的指针数组,并用另一个文件的输入填充该数组。不知道如何处理。

数据文件将首先包含条目数,然后是特定顺序的条目。

numOfEntries

lastName firstName studentID year gpa expGradYear

示例:

1

Doe John 12345678 高级 3.14159 2015

这是我目前的代码:

类.h

typedef enum {firstYear, sophomore, junior, senior, grad} class;

main.c

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

int main(){

//DBrecord is name for structure
struct DBrecord{
int DBrecordID;     //ID for each entry, range 0-319
char *last;         //student last name
char *first;        //student first name
char studentID[8];  //student ID
int age;            //student age
class year;         //year in school
float gpa;          //GPA
int expGradYear;    //expected graduation year
};
int numEntries;     //total number of entries, first num in data file
struct DBrecord **ptrToDB;

//scan first int in data file and assign to numEntries
scanf("%d", &numEntries);

//allocate memory for structures, each is 36 bytes
*ptrToDB = malloc (sizeof(struct DBrecord) * numEntries);

//free allocated memory
free(ptrToDB);

//build an array of pointers to dynamically allocated structures
//fill that array with input from data file

//build 7 arrays of pointers to DBrecords, one for each field except DB ID
//sort each a different way
//note the 7 arrays are pointers, no copying

//print each of the 7 sorted arrays

return 0;
}

【问题讨论】:

  • 如果您要内联编辑您的原始帖子,甚至不赞成我的回答,我就出局了。
  • @KevinDTimm 冷静你的喷气机人,你还没有完全回答我的问题。一步一步来。那我就给你点赞吧。
  • 您在没有评论的情况下进行了编辑 - 实现了我的 mod - 更多内容

标签: c pointers memory-management data-structures


【解决方案1】:

我可以给你一些关于如何看待这个问题的sn-ps。

首先 - 我会避免对任何变量使用 class 名称,因为在许多面向对象的编程语言(包括 C++)中,它是一个关键字,不能是变量的名称。

结构 DBrecord

使用 typedef 可能是个好主意。然后你可以声明一个结构变量而不使用“struct DBrecord”,只使用“DBrecord”。但这是可选的。这就是它的外观:

typedef struct {
   int DBrecordID; // ID for each entry
   char *lastName;
   char *firstName;
   char studentID[8];
   ...
} DBrecord;

从文件加载

在这个作业中,你有文件开头的记录数,所以你不需要“额外”关心它。只需加载它。

假设文件是​​这样的:

2
Doe John 12345678 senior 3.14159 2015
Carl Boss 32315484 junior 2.71 2013

因此,您对文件所做的第一件事就是打开它。

处理文件的可移植方式是使用 FILE 指针。让我展示一下(必须包含stdio.h):

FILE *filePtr; // Define pointer to file
if((filePtr = fopen("records.txt", "r")) == NULL) // If couldn't open the file
{
   printf("Error: Couldn't open records.txt file.\n"); // Printf error message
   exit(1);  // Exit the program
}

然后您可以使用 fgets() 逐行读取或 fgetc() 逐行读取您的文件。这是您可以读取记录数的方式(请记住,它在第一行,我们刚刚打开了文件 - 我们在文件的开头):

char buffer[100]; // Define the buffer
fgets(buffer, 100 /* size of buffer */, filePtr);

现在缓冲区包含第一行(没有 \n 字符) - 记录数。继续将 num 的字符转换为整数(这里还必须包含 stdlib.h):

int numOfRecords = atoi(buffer);

分配足够的 DBrecords

现在您知道了记录的数量,您可以为它们分配足够的空间。我们将使用指针数组。

DBrecord **recs;
recs = (DBrecord **) malloc(sizeof(DBrecord *) * numOfRecords);

现在我们已经创建了指针数组,所以现在我们需要将每个单独的指针分配为一个 DBrecord。使用周期:

int i;
for(i = 0; i < numOfRecords; i++)
{
   recs[i] = (DBRecord *) malloc(sizeof(DBrecord));
}

现在您可以像这样访问数组元素(= 单个记录):

recs[0]->lastname /* two possibilities */
*(recs[0]).lastname

以此类推。

用文件中的值填充数组

现在您知道完成作业所需的一切。这样你就可以填充数组了:

int i;
for(i = 0; i < numOfRecords; i++)
{
   // Content of cycle reads one line of a file and parses the values into recs[i]->type...
   /* I give you small advice - you can use fgetc(filePtr); to obtain character by character from the file. As a 'deliminer' character you use space, when you hit newline, then the for cycle continues.
   You know the order of stored values in the file, so it shouldn't be hard for you.
   If you don't get it, let me now in comments */
}

现在是不是更清楚了?

编辑:文件名作为主要参数

通常有两种方法可以将参数(值)“传递”给程序。它们是:

./program < records.txt   // Here the file's name is passed to program on stdin
./program records.txt    // Here the file's name is passed as value in `argv`.

如果你可以选择,我强烈推荐你第二个。因此,您需要将 main 定义为:

int main(int argc, char *argv[])  // this is important!
{
   // code

   return 0;
}

argc 是整数,表示传递给程序的参数数量。 argv 是存储它们的数组。请记住,第一个参数是程序的名称。因此,如果您需要检查它,请执行以下操作:

if(argc != 2)
{
  printf("Number of arguments is invalid\n");
  exit(1); // exit program
}

那么你只需将argv[1] 放入fopen 函数中,而不是字符串“records.txt”。

编辑 2:从标准输入读取文件名

必须采用另一种方法,如果记录文件的名称通过./program &lt; records.txt 传递给程序,这意味着“records.txt”(不带引号)将被传递(重定向)到程序的标准输入。

因此,为了解决这个问题,您可以这样做:

char filename[50]; // buffer for file's name
scanf("%s", &filename); // reads standard input into 'filename' string until white character appears (new line, blank, tabulator).

然后你在filename 字符串中有你想要的文件名。

【讨论】:

  • 如果在程序运行时加载文件,例如./a.out &lt; dataFile,我将如何逐行或按字符读取。为了使用fgets 等,我不需要一个文件来指向吗?
  • 已添加说明。请告诉我——你只是不专心,还是你的老师在解释上有“问题”,还是他想让你提前学习? :-)
  • 老师在解释任何事情时都有一个极端的问题。相反,她将我们引向互联网。而且她不做作业,是从别处传下来的,她也不知道怎么解释。几乎是迄今为止我上过的最差的课程之一。而且我别无选择,程序将运行./a.out &lt; dataFile
  • 我添加了第二种可能性:-) 无论如何,我不羡慕你。这些科目应该由懂的人去学,否则会很痛苦。编程是基于逻辑的,需要逻辑解释……没关系,现在清楚了吗?
  • @Mimars 你确定 *recs = malloc(sizeof(DBrecord) * numOfRecords) 正在分配一个指针数组吗?
【解决方案2】:

从哪里开始,从哪里开始.....

//allocate memory for structures, each is 36 bytes
mem = (double *)malloc(36*numEntries);
  1. malloc 应该是malloc (sizeof (struct DBRecord) * numEntries);
  2. 不要转换 malloc 的结果
    2a.你忘了stdlib.h
  3. 为什么要包含class.h
  4. 您的指针数组不是double,而是

    struct DBRecord **ptrToDB;
    *ptrToDB = malloc (sizeof (struct DBRecord) * numEntries);
    

这应该可以帮助您入门。

接下来,free() 应该是您在离开函数之前所做的最后一件事(是的,main 是一个函数)

你必须为下一部分插入一些代码,我不能为你做作业。

【讨论】:

  • 谢谢,我做了这些改变。我不明白如何用来自另一个文件的 DBrecord 输入填充动态分配的指针数组。
  • 我包含了 class.h 来定义枚举类型类。我想不需要单独的标题,但这就是我们一直在学习的方式。
  • 您没有在上面的代码中引用枚举。另外,我也会在 (a) 标头中声明结构(样式方面)
  • 我不是在结构中引用它吗? class year; 我有一个typedef 使classenum {firstYear, sophomore, etc} 文件中成为enum {firstYear, sophomore, etc} 的别名。还是我没有引用它,因为结构只是一个定义,还没有真正做任何事情?
猜你喜欢
  • 1970-01-01
  • 2016-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 2011-01-02
  • 2021-12-14
  • 1970-01-01
相关资源
最近更新 更多