【问题标题】:Reading the different columns of csv file in C在C中读取csv文件的不同列
【发布时间】:2015-07-27 12:49:05
【问题描述】:

我有一个 csv 文件,其中有 2 列命名;时间戳,SNR(整数值)。我必须编写一个首先询问用户输入的函数;用户想要什么价值? 示例文件:

 timestamp        ;       SNR   
 16:15:12:468     ;       15
 16:15:12:968     ;       20

例如:如果我输入 SNR,函数应该给我列号。信噪比; (即此处的第 2 列)以及 SNR 的值。

Output : Col. no. is 2         
            15       /* time difference of ((16:15:12:968)-(16:15:12:458) = 500ms between these two output values*/  
            20

但是这些值应该在某个时间间隔内作为输出给出。这意味着必须首先读取时间戳列,并且应该计算两个时间戳(当前和下一个)值之间的差异。现在应该在这两个时间戳值之间的差异间隔上给出 SNR 作为输出。我不想使用数组或结构,因为我不想存储值;我只是要求这些值在特定的时间间隔内传递给其他应用程序。

我写了以下代码。我可以获得用户输入并输出列号。文件,但我无法获取这些列的内容。我在我的程序中使用了 switch case,但我不明白为什么这个 switch case 不起作用。我还编写了一个函数来获取这两个时间戳之间的时间差,但我不知道如何在这个函数中组合它。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <time.h>
#define BUFFER_SIZE 1024
#define num_rows 100

const char* gettime(char* line, int num )
{
    const char* tok;
    for (tok = strtok(line, ";");tok && *tok;tok = strtok(NULL, ";\n"))
    {
        if (!num--)
        //Sleep(500);
        return tok;
    }
    return NULL;
}
const char* getSNR(char* line, int num )
{
    const char* tok;
    for (tok = strtok(line, ";");tok && *tok;tok = strtok(NULL, ";\n"))
    {
        if (!num--)
        //Sleep(500);
        return atoi(tok);
    }
    return NULL;
}

struct tm mytime;


int main ()
{
    int hh, mm;
    float ss, ms;
    mytime.tm_year = 2015 - 1900;               /* To initialize the struct tm*/
    mytime.tm_mon = 6;
    mytime.tm_mday = 15;
    int count;
    int value;
    char text[25];
    char *buffer;
    FILE *fp;
    char *token;
    char *tok;
    char line [100];
    char time_buffer[100];
    char **timestamp;                               /*Dynamic allocated array*/
    unsigned long ul_second_prev ;
    unsigned long ul_second_current;
    int i=0, j=0, k=1;
    int ui_time_diff, ui_SNR;
    time_t time_prev, time_current;                 /*Dynamic allocated array*/
    int timediff ;
    timestamp = malloc(num_rows*sizeof(char*));


if ((timestamp)== NULL)
    {
        printf("Error: out of memory");
    }

if ((fp=fopen("testfile.csv", "r"))==NULL)
{
    printf ("file cannot be opened");
    return 1;
}


buffer = malloc (BUFFER_SIZE); /*Allocate memory in buffer to read the file*/

if (buffer == NULL)
{
    printf("Error: Out of Memory");
    return 1;
}


    fgets(line, BUFFER_SIZE, fp);
    printf ("%s", line);
    printf ("enter your input\n");
    scanf("%s" , &text);
for (tok = strtok(line, ";");tok && *tok;tok = strtok(NULL, ";\n"))
{
        value = strcmp (tok, text);
        if(value ==0)
            printf("col. no. is %d", k);
        else k++ ;
}

while (fgets(line, BUFFER_SIZE, fp))
{

    char* tmp = strdup(line);

switch (k)
{
    case 1:
        gettime(tmp, 1);
        printf ( "%s",tok );
        break;
    case 2:
        getSNR(tmp, 2);
        printf ( "%s",tok );
        break;
}
free(tmp);
}

【问题讨论】:

  • SNR 应该是多少??
  • SNR 只是 int 值,例如 15、20、25 等。
  • 然后只写“值”而不是“信噪比”。当你问一个问题时,要笼统,不要使用只有你理解的术语。您还应该给出一些输入以及期望和实际输出的示例。
  • 请缩进代码以使其可读...... volatile 应该在这里做什么?我没有看到任何信号或硬件寄存器访问......哦,您输入格式中的分号在哪里?有点混乱……
  • @AntoineL 逗号就是逗号。是的,通常的做法是调用任何 csv,只要它具有使用 some 分隔符的值的行,但这并不能使它正确....在真正的 csv 中,一个包含逗号的值必须用双引号括起来...

标签: c csv


【解决方案1】:

除了无数未使用的变量和至少一个未使用的包含 (&lt;windows.h&gt;) 之外,gcc 还提供了这些可能指出您的问题的警告:

> gcc -std=c99 -Wall -Wextra -pedantic -oq q.c
q.c: In function ‘getSNR’:
q.c:26:9: warning: return makes pointer from integer without a cast
         return atoi(tok);
         ^
q.c: In function ‘main’:
q.c:84:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[25]’ [-Wformat=]
     scanf("%s" , &text);
     ^
q.c:96:5: warning: implicit declaration of function ‘strdup’ [-Wimplicit-function-declaration]
     char* tmp = strdup(line);
     ^
q.c:96:17: warning: initialization makes pointer from integer without a cast
     char* tmp = strdup(line);
                 ^
q.c:110:1: error: expected declaration or statement at end of input
 }
 ^

您的getSNR() 返回一个整数,但声明返回一个字符指针(又名:字符串)。您丢弃返回值,只需将(未初始化的!)char *tok(应为const 以获取返回值)提供给%s 格式说明符。

在您的scanf 中,除了使用错误的指针类型(这就是警告的内容)之外,您还有缓冲区溢出。欢迎饼干。 永远不要使用scanf("%s", ...)没有方法可以判断它将读取多少数据。在这种情况下,请在此处使用fgets(text, 25, stdin)

在编写 C 语言时,你应该学习两件事:第一,准确和精确,而不是反复无常。其次,让您的编译器警告一切(必要时使用适当的开关)。编译器警告在 98% 的情况下意味着编程错误或错误。

话虽如此,拥有 2 个几乎相同的功能是很愚蠢的。做这样的事情:

const char* getfield(char* line, int num )
{
    const char* tok;
    for (tok = strtok(line, ";");tok && *tok;tok = strtok(NULL, ";\n"))
    {
        if (!num--)
        return tok;
    }
    return NULL;
}

这个循环还是有点奇怪,但这是一个风格问题......然后稍后(注意你实际上是分配从你的函数返回的值):

while (fgets(line, BUFFER_SIZE, fp))
{
    switch (k)
    {
        case 1:
            tok = getfield(line, 1);
            printf ( "%s",tok );
            break;
        case 2:
            tok = getfield(line, 2);
            printf ( "%d",atoi(tok) );
            break;
    }
}

还请注意,您使用的分配的tmp 没有任何意义,因为您的line 缓冲区无论如何都会在循环的下一次迭代中被覆盖。那么为什么要复制呢?

【讨论】:

  • @Felix Palmen:非常感谢您的解释和更正。您能否解释一下 char* tmp 中提到的这两个警告,即什么是函数“strdup”的隐式声明以及“初始化使指针从没有强制转换的整数”是什么意思?
  • @learningpal 您忘记包含&lt;string.h&gt; 以使用strdup()&lt;string.h&gt; 声明了原型,因此编译器知道函数接受什么参数以及返回什么类型。如果您在没有声明原型的情况下使用该函数,则它隐式声明为返回int(出于历史原因)。这就是第一个警告的内容。第二个警告是后续 ...假定返回int,但您将返回值分配给char *。因此,当您包含&lt;string.h&gt; 时,这两个警告都会消失。但无论如何,strdup() 在您的代码中是不必要的。
  • 非常感谢。非常感谢。
  • 我试图实现你的代码。我更改了forloop 以将文本输入与while 进行比较,但是当我输入timestamp为什么它不比较并给我列号时,我没有得到它。其中。代码如下:printf ("enter your input\n"); fgets(text, 25, stdin); tok = strtok(line, ";"); while (tok!= NULL) { value = strcmp(tok, text); if (value ==0) printf ("col. no. is %d\t", k); else tok = strtok(NULL, ";\n"); k =k+1;} 因为我没有得到我的上校。不。值(k),我也无法实现开关盒。我没有收到错误。
  • fgets 包括目标缓冲区中的newline 字符(\n on *nix,\r\n on windows)。见the accepted answer here
猜你喜欢
  • 2019-08-16
  • 2015-07-22
  • 1970-01-01
  • 2020-06-11
  • 1970-01-01
  • 1970-01-01
  • 2022-06-30
  • 1970-01-01
相关资源
最近更新 更多