arrays - 将 CSV 文件读入结构的动态数组 C
问题描述
我对C相当陌生。我正在尝试读取.CSV
文件,然后解析每一行,然后将数据存储在指向结构的指针的动态数组中。不幸的是,我在实现中的某个地方出错了,这导致了无限循环。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dataSet {
char ID;
char postcode;
int population;
char contact;
double x;
double y;
}data;
int main(int argc, char* argv[]) {
char line[100] = "";
int count = 0;
int each = 0;
data *allData = NULL;
data *temp = NULL;
FILE *file = fopen("dataset.csv", "r");
if (file == NULL)
{
printf("Error! File null");
return 1;
}
while (fgets(line, sizeof line, file))
{
if(NULL == (temp = realloc(allData, sizeof(*allData) * (count + 1))))
{
fprintf(stderr, "realloc problem\n");
fclose(file);
free(allData);
return 0;
}
allData = temp;
if (6 == scanf(line, "%s, %s, %d, %s, %lf, %lf",
&allData[count].ID,
&allData[count].postcode,
&allData[count].population,
&allData[count].contact,
&allData[count].x,
&allData[count].y)) {
count++;
}
else {
printf("Problem with data\n");
}
}
fclose(file);
for (each = 0; each < count; each++)
{
printf("%s, %s, %d, %s, %lf, %lf\n",
&allData[count].ID,
&allData[count].postcode,
&allData[count].population,
&allData[count].contact,
&allData[count].x,
&allData[count].y);
}
free(allData);
return 0;
}
任何帮助或提示将不胜感激。
解决方案
[s]scanf()
是一个讨厌的功能。一旦失败,您就没有足够的控制权。问题是:条件太多:输入可能不正确,或者目标不够大。即使用 阅读完整的行fgets()
并在之后对其进行解析,也只会让您跳过完整的行;另外:行缓冲区大多是固定大小的,并且fgets()
可以读取不完整的行。保持完全控制的一种方法是基于字符的读取。这可能意味着有限状态机。
一个更简单的阅读器(使用零状态机)可能是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct omg {
char o;
int m;
char g[11];
};
struct wtf {
unsigned size;
unsigned used;
struct omg *array;
};
#define INITIAL_SIZE 7
struct wtf read_stuff(char *name)
{
FILE *fp;
unsigned icol,irec,len;
char buff[123];
struct wtf this = {0,0,NULL};
fp = fopen(name, "rb" );
if (!fp) return this;
for (icol=irec=len=0; ; ) {
int ch;
if (this.used >= this.size) {
size_t newsize;
struct omg *tmp;
newsize = this.size? this.size*2: INITIAL_SIZE;
fprintf(stderr, "Realloc(%zu)\n", newsize);
tmp = realloc(this.array, sizeof *this.array * newsize);
this.array = tmp;
this.size = newsize;
}
ch = getc(fp);
switch(ch) {
case '\r' : continue;
/* End of field or record: terminate buffer */
#if 0
case ',' :
#else
case '\t' :
#endif
case '\n' :
buff[len] = 0;
break;
case EOF :
goto done;
/* Normal character: assign to buffer
** You may want to report too long fields here
*/
default:
if (len >= sizeof buff -2) continue;
buff[len++] = ch;
continue;
}
/* When we arrive here, we have a new field. Let's process it ...*/
switch (icol) {
case 0: /* Assign first field here from buff[], (dont forget to check len!) */
this.array[this.used].o = buff[0];
break;
case 1: /* Assign second field from buff[], this may need some additional checks
** You may want to avoid sscanf() here ...
*/
sscanf(buff, "%d", &this.array[this.used].m );
break;
case 2: /* Assign third field from buff[] */
if (len >= sizeof this.array[this.used].g)
len = sizeof this.array[this.used].g -1;
memcpy (this.array[this.used].g, buff, len);
this.array[this.used].g[len] = 0;
break;
default: /* Ignore excess fields
** You may want to report hem.
*/
break;
}
/* Do some bookkeeping */
len = 0;
if(ch == '\n') {
/* You may want to check if icol==2, here */
icol=0; irec++; this.used++;
}
else icol++;
}
done:
fclose(fp);
/* You could do a final realloc() here */
return this;
}
int main(int argc, char **argv)
{
struct wtf result;
unsigned idx;
result = read_stuff(argv[1] );
fprintf(stderr, "Result=%u/%u\n", result.used,result.size);
for (idx=0; idx < result.used; idx++) {
printf("%c %d %s\n"
, result.array[idx].o
, result.array[idx].m
, result.array[idx].g);
if (idx >= 10) break;
}
return 0;
}
推荐阅读
- msmq - MSMQ enumerator.RemoveCurrent 退出消息队列迭代
- c# - 我可以让用户选择要导入 Datagridview 的 excel 文件吗?
- ckeditor5 - 在 CKEditor 5 的 modifyselection 中更改参数的任何副作用?
- javascript - 无法读取属性“未定义的导航”
- .net - 无法获得任何响应 - 发送 HTTP 标头后服务器无法附加标头
- javascript - 与 Safari 9 的 Javascript 兼容性
- php - 致命错误:未捕获的 SoapFault 异常:[HTTP] 发送 HTTP SOAP 失败
- vue.js - 如何使用 vuetify image srcset - vuejs
- maven - gitlab中的maven settings.xml重复
- google-cloud-firestore - firebase friendlychat-web 如何在新集合中添加数据?