【问题标题】:Reading a csv file into a struct in C using scanf使用scanf将csv文件读入C中的结构
【发布时间】:2019-01-31 12:46:31
【问题描述】:

我在从 csv 数据文件读取到 C 中二叉搜索树的节点时遇到问题。似乎实际上没有任何数据被读取到结构中。我现在使用的代码只是试图从 csv 文件中读取一行数据,然后我才能将其放大以读取整个内容,但即使这样我也没有得到结果。我知道此代码中可能存在许多大问题,因为我对语言不是非常胜任,但是任何见解都将不胜感激。

typedef struct{
  struct bst_t *left;
  struct bst_t *right;
  data_t data;
} bst_t;

这是我的阅读功能

void readdata(bst_t node){
  while(
  scanf("%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],
   %[^,],%[^,],%[^,],%[^,] ,[^,],%[^,],%[^,] ... ) == 14);
}

这是我的打印功能

void printdata(bst_t node){
  printf("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s \n"...);
}

但是我的输出很简单:

-bash-4.1$ print

,,,,,,,,,,.,(@,,▒

我还没有面临的另一个问题是文件中的某些数据在条目中会有逗号,我将如何“忽略”这些逗号,以便它们显示为数据而不是文件中的分隔符?

再次感谢任何帮助。

编辑:这是我调用函数的地方:(即 main)

int main(int argc, char *argv[]) {
bst_t node;
readdata(*node);
printdata(node);
return 0;

}

新的编译器代码

print.c: In function 'main':
print.c:37: error: invalid type argument of 'unary *' (have 'bst_t')
print.c: In function 'readdata':
print.c:56: error: request for member 'node' in something not a structure     or union

这是完整的代码:

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


#define MAXSTRING 128


typedef struct{
  struct bst_t *left;
  struct bst_t *right;
  struct data_t data;
} bst_t;

void readdata(bst_t *node);
void printdata(bst_t node);

int main(int argc, char *argv[]) {
    bst_t node;
    readdata(&node);
    printdata(node);
    return 0;
}


void readdata(bst_t *node){
  while(
  scanf("%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,] \n",...) == 14)

}

【问题讨论】:

  • 请提供调用这两个函数的代码。
  • 请记住,在 C 中,函数的所有参数都是按值传递的,即它们是复制的,而函数只有一个副本可以处理。现在想想当你修改一个结构的副本时会发生什么,但原始结构仍然保持不变。
  • 而且,您将获得一个金星,因为您实际上验证了scanf 的回报。你会做得很好。只有其他建议是声明一个缓冲区(足够大的 2 倍),然后一次读取整行(例如 while (fgets (buffer, sizeof buffer, stdin) { if (sscanf (buffer, "%....", node.data.ID, ...) == 14) ... } 这样您就可以验证(1)行的读取;和(2)解析将行转换为变量。当然这是一个清洗,但如果 inputmatching 失败,您已经阅读了完整的行,可以继续下一个。
  • 我已经更新了主代码
  • 你需要:readData(&amp;node) 来做一个指针。但是,readData 也需要接受一个指针,如给定答案中所示...*node 是相反的:如果您已经有一个指针,那么您将获得的值。示例:int n; int* p = &amp;n; *p = 7; 将有效地将 7 分配给 n

标签: c csv struct scanf binary-search-tree


【解决方案1】:

read 函数只更新它接收到的局部变量node 作为参数。您必须将指针传递给新分配的结构:

void readdata(bst_t *node) {
    while (scanf(" %[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],[^,],%[^,],%[^,]",
                 node->data.ID, node->data.name, node->data.sex,
                 node->data.height, node->data.weight, node->data.team,
                 node->data.NOC, node->data.games, node->data.year,
                 node->data.season, node->data.city, node->data.sport,
                 node->data.event, node->data.medal) == 14) {
        continue;
    }
} 

你可以从main这样调用这个函数:

int main(int argc, char *argv[]) {
    bst_t node;
    readdata(&node);
    printdata(node);
    return 0;
}

但是请注意,这个函数是不安全的:它不能防止缓冲区溢出。

另请注意,它不能处理空字段,也不能处理嵌入逗号的字段。

要正确解析输入,您需要一个手动编码的解析器来处理特殊情况并提供精确的错误报告。

编辑:您发布的源代码有语法错误:

               node->data.event->node.data.medal) == 14)

应该是:

               node->data.event, node->data.medal) == 14)
        continue;

您应该通过将语句缩进 4 个空格并在二元运算符周围和 , 之后插入空格来格式化您的代码。

试试这个版本的readdata:(从网页复制粘贴)

void readdata(bst_t *node) {
    while (scanf(" %[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],[^,],%[^,],%[^,]",
                 node->data.ID, node->data.name, node->data.sex,
                 node->data.height, node->data.weight, node->data.team,
                 node->data.NOC, node->data.games, node->data.year,
                 node->data.season, node->data.city, node->data.sport,
                 node->data.event, node->data.medal) == 14) {
        continue;
    }
} 

【讨论】:

  • 我会在第一个 " %[^,].." 之前添加一个 space 并从末尾删除 '\n' 以防止非 POSIX 文件结尾。
  • @DavidC.Rankin:很好的建议,虽然非 Posix 文件结尾不会造成问题。跳过初始空格而不是尾随空格可以更好地进行交互式测试,因为可以在输入行时对其进行处理。
  • 由于字符串长度是作为宏给出的,我们可以有像"... %" #MAXSTRINGBASE "[^,] ..." 这样的模式,其中宏定义为最大长度而不终止空字符,并让#define MAXSTRING (MAXSTRINGBASE + 1) 正确设置数组(当然,基一定不能让这个正常工作的计算......)。
  • @Aconcagua:不幸的是,您的建议不起作用:stringize 运算符仅适用于宏扩展,并且会扩展为 "(MAXSTRINGBASE + 1)",而不是实际值。格式字符串可以先用snprintf 构造,然后再与fscanf() 一起使用,但这只能解决部分问题。
  • 我试图更新我的代码来实现这一点,但得到一个编译器错误,如原始帖子所示(不确定如何格式化 cmets)。
猜你喜欢
  • 2013-12-16
  • 2020-05-05
  • 1970-01-01
  • 2018-07-06
  • 1970-01-01
  • 2013-12-11
  • 2021-02-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多