1

I have a csv file which has 2 columns named; timestamp, SNR (int values). I have to write a function which asks first the user input; which value user wants? sample file:

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

For Example: If I enter SNR, the function should give me the column no. of SNR; (that is column 2 here) as well as the values of 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

But these values should be given as output on a certain time interval. This implies that the timestamp column has to be read first and the difference between the two timestamp (current & next) values should be calculated. Now the SNR should be given as output on the interval of difference between these two timestamp values. I do not want to use array or structures because I don’t want to store values; I just require these values to pass on to other application on certain time interval.

I wrote the following code. I could get the user input and output the column no. of file, but I am not able to get the content of these columns. I used the switch case in my program, but I am not getting why this switch case is not working. I have also written a function to get the time difference between these two timestamps, but I am not getting how to combine it in this function.

#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);
}
learningpal
  • 309
  • 1
  • 8
  • 17
  • What is SNR supposed to be ?? – Jabberwocky Jul 27 '15 at 12:58
  • SNR are just int values like 15,20,25 and so on. – learningpal Jul 27 '15 at 13:06
  • 1
    Then just write "value" instead of "SNR". When you ask a question be general and don't use terms only you understand. You also should give an example of some input and desired and actual output. – Jabberwocky Jul 27 '15 at 13:07
  • Did some changes. i hope it is clearer now. – learningpal Jul 27 '15 at 13:20
  • Whay do you `strtok` on `;` when the separator is `,`? – Paul Ogilvie Jul 27 '15 at 13:23
  • 1
    And please indent the code so it's readable ... what is the `volatile` supposed to do here? I don't see any signals or hardware register accesses... Oh and where are the semicolons in your input format? A bit confusing... –  Jul 27 '15 at 13:50
  • @FelixPalmen: I mentioned that its a csv file, so didnt show the semicolons, but I added now for more clarity. – learningpal Jul 27 '15 at 13:59
  • I expected to find `,`s in a [comma-separated-value or.csv](https://en.wikipedia.org/wiki/Comma-separated_values) file. I suppose `;` is a comma here? – chux - Reinstate Monica Jul 27 '15 at 14:07
  • @chux: ya ; is acting like comma. I also tried first with "," in my code, but i was not getting output so I used ; – learningpal Jul 27 '15 at 14:13
  • @chux @PaulOgilvie CSV separators vary around the world: while `,` is standard in the USA and generally where `.` is the decimal separator, `;` is more common in continental Europe where the decimal separator is often `,`; this is shown in the last example in the Wikipedia page. – AntoineL Jul 27 '15 at 14:21
  • 1
    @AntoineL a comma is a comma. Yes, it's common practice to call anything csv as long as it has lines with values using *some* delimeter, but that doesn't make it correct.... in a real csv, a value containing a comma must be enclosed in double quotes... –  Jul 27 '15 at 14:41

1 Answers1

2

Ok apart from the myriads of unused variables and at least one unused include (<windows.h>), gcc gives also these warnings that probably point out your problems:

> 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
 }
 ^

Your getSNR() returns an integer, but is declared to return a character pointer (aka: string). You discard the return value and just feed an (uninitialized!) char *tok (which should be const to take the return value) to the %s format specifier.

In your scanf, apart from using the wrong pointer type (that's what the warning is about), you have a buffer overflow. Welcome crackers. NEVER EVER use scanf("%s", ...), there's no way to tell how much data it will read. Use fgets(text, 25, stdin) in that case here.

You should learn two things when programming C: First, be accurate and precise, not erratic. Second, let your compiler warn about everything (using the appropriate switches if necessary). A compiler warning means in 98% of the cases a programming error or bug.

That being said, it's silly to have 2 nearly identical functions. Do something like this:

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;
}

Still a bit strange this loop, but that's a question of style ... and then later (note that you actually assign the value returned from your function):

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;
    }
}

Also note the allocated tmp you used doesn't make any sense, as your line buffer gets overwritten in the next iteration of the loop anyways. So why take a copy?

  • @ Felix Palmen: Thanks much for explanation and corrections. Can you please explain these two warnings mentioned in char* tmp that what is implicit declaration of function ‘strdup’ and what does ' initialization makes pointer from integer without a cast' mean? – learningpal Jul 27 '15 at 20:02
  • 1
    @learningpal you forgot to include `` in order to use `strdup()`. `` declares the prototype, so the compiler knows what arguments the function takes and what type it returns. If you use the function without a declared prototype, it is *implicitly* declared as returning an `int` (for historical reasons). That's what the first warning is about. The second warning is a *followup* ... it's assumed to return `int` but you assign the return value to a `char *`. So both warnings will disappear when you include ``. But the `strdup()` is unnecessary in your code anyways. –  Jul 27 '15 at 20:08
  • Thanks a lot. Quite appreciate it. – learningpal Jul 27 '15 at 20:27
  • I tried to implement your code. I changed the `for`loop for comparing the text input with `while`, but I am not getting that when I enter my input such as `timestamp`why it does not compare and give me the column no. of it. The code is as follows: `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;}` As I am not getting my col. no. value (k), i am not able to implement the switch case too. I am not getting error. – learningpal Jul 28 '15 at 11:15
  • `fgets` includes the `newline` character(s) in the target buffer (`\n` on *nix, `\r\n` on windows). See [the accepted answer here](http://stackoverflow.com/questions/31660585/c-strcmp-not-returning-0-for-equal-strings) –  Jul 28 '15 at 11:20
  • thanks much I resolved this `fgets` issue. I debugged the code and after getting the value of column no., it jumps to `while (fgets(line, BUFFER_SIZE, fp))` but it doesn't execute switch case statement. It jumps again and again to `while (fgets(line, BUFFER_SIZE, fp)` to read lines but not executing the switch commands in while loop. – learningpal Jul 28 '15 at 13:06