C 编程:从文件中读取数据,动态分配内存,将内容放入结构数组

如何解决C 编程:从文件中读取数据,动态分配内存,将内容放入结构数组

这是我在 stackoverflow 上的第一篇文章。我是一名学习 C 的 CS 学生,我在处理这个问题时遇到了一些问题。另外,我要说的是我知道的很少,所以如果我放在这里的任何东西被认为是愚蠢或无知的,那绝对不是我的本意

我知道还有其他类似的帖子,但到目前为止,我觉得我已经尝试了很多修改,但结果都是一样的。

我得到一个文本文件,其中每一行都包含 studentName(tab)gpa。文件的总大小未知,这个我必须使用动态内存分配。

文本文件格式示例

Jordan  4.0
Bhupesh 2.51

程序的一般步骤

为了避免尴尬,我将省略许多细节,但我将简要概述我正在努力解决的过程:

 1.) Create dynamic memory array to hold struct for each line
 2.) Start looping through file
 3.) check the current size of the array to see if reallocation is necessary
 4.) Create dynamic array to hold name
 5.) Place name and gpa into struct
 6.) rinse & repeat

最后,最后一件事。当达到我的初始分配内存限制并且程序尝试从堆中重新分配更多内存时,就会发生错误。

Screenshot of error being thrown in clion debugger

我的代码如下所示:

#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2

struct Student {
    float gpa;
    char * name;
};

// read the file,pack contents into struct array
struct Student * readFileContents(char *filename,int *rowCounter) {

    // setup for loop
    int maxDataSize = ROW_COUNT;
    float currentStudentGpa = 0;
    char studentNameBuffer[BUFFER_SIZE];

    // initial structArray pre-loop
    struct Student * structArray = calloc(maxDataSize,sizeof(*structArray));

    FILE *pFile = fopen(filename,"r");
    validateOpenFile(pFile);


    // loop through,get contents,of eaach line,place them in struct
    while (fscanf(pFile,"%s\t%f",studentNameBuffer,&currentStudentGpa) > 0) {
        structArray = checkArraySizeIncrease(*rowCounter,&maxDataSize,&structArray);
        structArray->name = trimStringFromBuffer(studentNameBuffer);
        structArray->gpa = currentStudentGpa;
        (*rowCounter)++,structArray++;
    }

    fclose(pFile);

    return structArray;
}

// resize array if needed
struct Student * checkArraySizeIncrease(int rowCount,int * maxDataSize,struct Student ** structArray) {

    if (rowCount == *maxDataSize) {
        *maxDataSize += ROW_COUNT;
        
        **// line below is where the error occurs** 
        struct Student * newStructArray = realloc(*structArray,*maxDataSize * sizeof(*newStructArray));
        validateMalloc(newStructArray);

        return newStructArray;
    }
    return *structArray;
}

// resize string from initial data buffer
char *trimStringFromBuffer(char *dataBuffer) {

    char *string = (char *) calloc(strlen(dataBuffer),sizeof(char));
    validateMalloc(string);
    strcpy(string,dataBuffer);

    return string;
}


再次,如果有人问过类似的问题,我深表歉意,但请知道我已经尝试了我在堆栈溢出时发现的大部分建议,但没有成功(我很清楚这是我糟糕的编程的结果C 中的技能水平)。

我现在将立即为我的强制性“关于 stackoverflow 的第一篇文章”烘焙做好准备。干杯!

解决方法

您正在重用 structArray 作为数组的基础指向 current 元素的指针。这行不通。我们需要两个变量。

有许多与动态数组相关的“松散”变量。定义一个 struct(例如下面的 dynarr_t)来包含它们并只传递 struct 指针会更简洁。

当您复制字符串时,您必须分配 strlen + 1 [not 只是 strlen]。但是,整个函数执行 strdup 已经执行的操作。

我试图尽可能地节省,但我不得不重构代码以包含所有必要的更改。

通过将 sizeof(*structArray) 传递给 arrnew 函数,这允许将结构用于任意大小的数组元素。

无论如何,这是代码:

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

#define sysfault(_fmt...) \
    do { \
        printf(_fmt); \
        exit(1); \
    } while (0)

#define EXIT_CODE_FAIL 1
#define ROW_COUNT 10
#define BUFFER_SIZE 255
#define VALID_ARG_COUNT 2

struct Student {
    float gpa;
    char *name;
};

// general dynamic array control
typedef struct {
    void *base;                         // base address
    size_t size;                        // bytes in array element
    size_t count;                       // current number of used entries
    size_t max;                         // maximum number of entries
    size_t grow;                        // number of entries to grow
} dynarr_t;

// arrfind -- return pointer to array element
void *
arrfind(dynarr_t *arr,size_t idx)
{
    void *ptr;

    ptr = arr->base;
    idx *= arr->size;
    ptr += idx;

    return ptr;
}

// arrnew -- create new array control
dynarr_t *
arrnew(size_t siz,size_t grow)
// siz -- sizeof of array element
// grow -- number of elements to grow
{
    dynarr_t *arr;

    arr = calloc(1,sizeof(*arr));
    if (arr == NULL)
        sysfault("arrnew: calloc fail -- %s\n",strerror(errno));

    arr->size = siz;
    arr->grow = grow;

    return arr;
}

// arrgrow -- grow array [if necessary]
// RETURNS: pointer to element to fill
void *
arrgrow(dynarr_t *arr)
{
    void *ptr;

    // grow array if necessary
    // NOTE: use of a separate "max" from "count" reduces the number of realloc
    // calls
    if (arr->count >= arr->max) {
        arr->max += arr->grow;
        arr->base = realloc(arr->base,arr->size * arr->max);
        if (arr->base == NULL)
            sysfault("arrgrow: realloc failure -- %s\n",strerror(errno));
    }

    // point to current element
    ptr = arrfind(arr,arr->count);

    // advance count of elements
    ++arr->count;

    return ptr;
}

// arrtrim -- trim array to actual number of elements used
void
arrtrim(dynarr_t *arr)
{

    arr->base = realloc(arr->base,arr->size * arr->count);
    if (arr->base == NULL)
        sysfault("arrtrim: realloc failure -- %s\n",strerror(errno));

    arr->max = arr->count;
}

void
validateMalloc(void *ptr)
{

    if (ptr == NULL) {
        perror("validateMalloc");
        exit(1);
    }
}

void
validateOpenFile(FILE *ptr)
{

    if (ptr == NULL) {
        perror("validateOpenFile");
        exit(1);
    }
}

// resize string from initial data buffer
char *
trimStringFromBuffer(char *dataBuffer)
{

#if 0
#if 0
    char *string = calloc(1,strlen(dataBuffer));
#else
    char *string = calloc(1,strlen(dataBuffer) + 1);
#endif
    validateMalloc(string);
    strcpy(string,dataBuffer);
#else
    char *string = strdup(dataBuffer);
    validateMalloc(string);
#endif

    return string;
}

// read the file,pack contents into struct array
dynarr_t *
readFileContents(char *filename)
{
    dynarr_t *arr;

    // setup for loop
    float currentStudentGpa = 0;
    char studentNameBuffer[BUFFER_SIZE];
    struct Student *structArray;

    arr = arrnew(sizeof(*structArray),10);

    FILE *pFile = fopen(filename,"r");
    validateOpenFile(pFile);

    // loop through,get contents,of eaach line,place them in struct
    while (fscanf(pFile,"%s\t%f",studentNameBuffer,&currentStudentGpa) > 0) {
        structArray = arrgrow(arr);
        structArray->name = trimStringFromBuffer(studentNameBuffer);
        structArray->gpa = currentStudentGpa;
    }

    fclose(pFile);

    arrtrim(arr);

    return arr;
}
,

我认为您的问题在于重新分配大小的计算。而不是使用sizeof(*newStructArray),你真的不应该使用你的指针类型的大小吗?我会把它写成 realloc(*structArray,*maxDataSize * sizeof(struct Student *))

这里还有很多我永远不会做的其他事情 - 将所有这些变量作为指针传递给 checkArraySizeIncrease 通常是一个坏主意,因为它可以掩盖事情正在发生变化的事实,例如。

,

为字符串分配缓冲区存在问题

char *string = (char *) calloc(strlen(dataBuffer),sizeof(char));

应该是:

char *string = (char *) calloc(1 + strlen(dataBuffer),sizeof(char));

因为 C 字符串在末尾需要额外的 0 字节。 没有它,如下操作:

strcpy(string,dataBuffer);

可能会损坏缓冲区后的数据,可能会弄乱 malloc() 元数据。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-
参考1 参考2 解决方案 # 点击安装源 协议选择 http:// 路径填写 mirrors.aliyun.com/centos/8.3.2011/BaseOS/x86_64/os URL类型 软件库URL 其他路径 # 版本 7 mirrors.aliyun.com/centos/7/os/x86
报错1 [root@slave1 data_mocker]# kafka-console-consumer.sh --bootstrap-server slave1:9092 --topic topic_db [2023-12-19 18:31:12,770] WARN [Consumer clie
错误1 # 重写数据 hive (edu)&gt; insert overwrite table dwd_trade_cart_add_inc &gt; select data.id, &gt; data.user_id, &gt; data.course_id, &gt; date_format(
错误1 hive (edu)&gt; insert into huanhuan values(1,&#39;haoge&#39;); Query ID = root_20240110071417_fe1517ad-3607-41f4-bdcf-d00b98ac443e Total jobs = 1
报错1:执行到如下就不执行了,没有显示Successfully registered new MBean. [root@slave1 bin]# /usr/local/software/flume-1.9.0/bin/flume-ng agent -n a1 -c /usr/local/softwa
虚拟及没有启动任何服务器查看jps会显示jps,如果没有显示任何东西 [root@slave2 ~]# jps 9647 Jps 解决方案 # 进入/tmp查看 [root@slave1 dfs]# cd /tmp [root@slave1 tmp]# ll 总用量 48 drwxr-xr-x. 2
报错1 hive&gt; show databases; OK Failed with exception java.io.IOException:java.lang.RuntimeException: Error in configuring object Time taken: 0.474 se
报错1 [root@localhost ~]# vim -bash: vim: 未找到命令 安装vim yum -y install vim* # 查看是否安装成功 [root@hadoop01 hadoop]# rpm -qa |grep vim vim-X11-7.4.629-8.el7_9.x
修改hadoop配置 vi /usr/local/software/hadoop-2.9.2/etc/hadoop/yarn-site.xml # 添加如下 &lt;configuration&gt; &lt;property&gt; &lt;name&gt;yarn.nodemanager.res