Parsing a csv file crashing reading array of pointers

This is a discussion on Parsing a csv file crashing reading array of pointers within the C Programming forums, part of the General Programming Boards category; Hello everyone, First of all, thanks in advance for your help. I am trying to write a program that will ...

  1. #1
    Registered User
    Join Date
    Apr 2009
    Posts
    10

    Parsing a csv file crashing reading array of pointers

    Hello everyone,

    First of all, thanks in advance for your help.

    I am trying to write a program that will examine my T-Mobile csv file. A csv file is a comma seperated values file which in my case contains the date, time, caller ID info, number, and duration of every call I've made in the past month, along with some other junk info. What I am trying to do is convert the file from that, into an output file that will show each number only once and the total number of minutes that I've spoken to each person.

    This is a sample of the beginning of the csv file:
    Code:
    "LOCAL AIRTIME, LONG DISTANCE and INTERNATIONAL CHARGES"
    
    Date,Destination,Time,Number,Call Type,Minutes,Airtime,Toll,Total
    "5/28/10","Ptstlucies, FL","12:47 AM","772-777-7777","","1","-","-","-"
    "5/28/10","Pueblo, CO","12:50 AM","719-588-8888","","1","-","-","-"
    "5/28/10","Stuart, FL","12:51 AM","772-999-9999","","3","-","-","-"
    This, is the code that I have written:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define BUFSIZE 100
    
    char *strsh(char *lstr, int charnum);
    
    char *strsh(char *lstr, int charnum){       //This function will shift the string "lstr" to the left charnum characters
         int i = 0;                             // E.g. The string "This is a string" feed to the function with charnum equal to 5
                                                // will make the string become "is a string"
         while ( charnum <= strlen(lstr)){
               
               lstr[i] = lstr[charnum];
               i++;
               charnum++;
               }
         //printf("%s", lstr);
         return lstr;
    }
    
    int main(int argc, char *argv[])
    {
      char buf[ BUFSIZE ] = {0};       //This is the buffer into which data from the file is read
      char buf2[ BUFSIZE ] = {0};      //This is the backup buffer which is where buf is copied when it is split with strtok
      int counter;
      int counter2;
      int tempcount;
      int bufcount;
      char * pch;                      //This is what the tokens from buf are stored into with strtok.
      int arraySize = 200;
      //char *NumArray[50] = (char *)malloc(sizeof(char *));    // This is the old declaration of NumArray
      char **NumArray = (char **)malloc(arraySize * sizeof(char *));    //Attempting to make an array of pointers to store the phone numbers.
      int n = 0;
      int m = 0;
      int q = 0;
      //int azer = 0;
      //NumArray[0] = "Testing";
      //printf("\n\n %s \n\n", NumArray[0]);
      //for(azer = 0; azer < 50; azer++){
      //         strcpy(NumArray[azer], NULL);
      //         }
      
      
      FILE *in = fopen("calls.csv", "r");         //Open the csv file with the phone numbers and times
          if (in == NULL) {
                 perror("Unable to open file\n");
                 exit(EXIT_FAILURE);
          }
          
      FILE *out = fopen("output2.txt", "w");     //Open the output file into which we will put the parsed data
          if (in == NULL) {
                 perror("Unable to open file\n");
                 exit(EXIT_FAILURE);
          }  
          
      for( counter = 0; fgets( buf, BUFSIZE, in); counter++ ){     //Keep looping until we've read the entire file with fgets()
    
           if(counter >= 3){                                // Skip the first 3 lines because those don't contain phone data
           strsh(buf, 11);                                  // Get rid of the date and time of the call and other junk data
           tempcount = 0;
           bufcount = 0;
                     while(tempcount < 3){                  //While loop to remove more junk from the begining of the file, since
                          if(buf[bufcount] == '\"')         //The next piece of data varies in size, we have to count how many quotes
                          tempcount++;                      //There are up to the end of the junk data and then remove however many characters
                          bufcount++;                       //in the third quote is.
                     }
           strsh(buf, (bufcount + 1));
           tempcount = 0;
           bufcount = 0;
                    while(tempcount < 6){                   //Find out how far it is to the end of the data we need so that we can
                         if(buf[bufcount] == '\"')          //Cut out the rest of the line with a \0
                         tempcount++;
                         bufcount++;
                    }
           buf[bufcount] = '\n';
           buf[(bufcount + 1)] = '\0';                      //Cutting off junk at end of line (See above)
           //printf("\n\ntempcount = %d bufcount = %d \n\n", tempcount, bufcount);
           //system("pause");
           for(counter2 = 0; counter2 < sizeof(buf); counter2++ ){      //This loop removes the quotes from what we have remaining in the line
                        if(buf[counter2] == '\"')
                           buf[counter2] = ' ';
           }
            if(buf[1] != ','){                                  //This will remove the last line of the file which contains no useful data and begins with a comma
                      strcpy(buf2, buf);                        //Backing up buf before we use strtok to break it up
                      pch = strtok(buf, ",");                   //Split buf at the commas
                      
                      m = 1;/*
                      for(n = 0; n < 50; n++){                  //This loop, which does not work is suppoed to check each number against everything
                            printf("Debug1\n");                 //in the array to determine if we've already stored the number but for some reason this 
                            if(strcmp(pch, NumArray[n]) == 0){  //keeps causing a segmentation fault
                            printf("Debug2\n");
                                   printf("pch is equal to NumArray \n");
                                   m = 0;
                            }
                      }
                      printf("m = %d \n", m);                       //This is debugging stuff if m == 1 then it's supposed to  
                      if(m == 1){                                   //store pch (the number from buf)into NumArray.
                           NumArray[q] = pch;
                           q++;
                           printf("Stored %d \n", q);
                           }*/
                      system("pause");                              //Pause to see the results of processing on this line
                      
                      puts(pch);                                    //Display data to the screen
                      fprintf(out, "%s", buf);                      //Write data to file
            }
           }
      }
      
      fclose(in);                  //Close the csv file
      fclose(out);                 //Close the output file.
      system("pause");             //Pause one more time for no particular reason.
      
      
      	
      return 0;                    //Return 0 to function main()
    }
    Once buf gets to the loop causing the segmentation fault, it looks like this:

    772-777-7777 , , 1

    and pch splits it at the comma, so what's being compared with NumArray[n] is

    772-777-7777

    Now I'm having trouble with 2, or maybe 3 parts. First of all, I need to declare an array of pointers (to strings). This array of pointers will hold the phone numbers that I extract from the file. I tried declaring it like this:

    char *NumArray[50];

    But the program crashed when I got to checking the contents of the array, so I thought that maybe I had to malloc space for the array (which is my second question), so I commented that out, and tried this:

    char **NumArray = (char **)malloc(arraySize * sizeof(char *));

    But I'm still crashing, and I don't even quite know that this is doing the same thing that I was doing before. So my first question is what is the best way, or the proper way, to declare an array of pointers (to strings)

    My second question is, do I need to, and if so how do I malloc space for the array properly?

    Last, how can I properly make the program check each element of the array against "pch" which is the phone number extracted from "buf". Currently I have this loop, which crashes the app:

    for(n = 0; n < 50; n++){
    printf("Debug1\n");
    if(strcmp(pch, NumArray[n]) == 0){
    printf("Debug2\n");
    printf("pch is equal to NumArray \n");
    m = 0;
    }
    }

    Again, thanks in advance for your help.

    -Primux

  2. #2
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    I believe the best thing to do, is to simplify your program's logic. Seems like the code is wading through waist deep snow.

    How many calls in a month would be an expected maximum?

    I'd start with a one line buffer and use fgets() to put one line of data, into the buffer, then remove the unwanted comma's and double quotes, etc. Scanf() could also be used, since the data is formatted, but scanf() can be "brittle".

    Have a struct defined above main() with the struct members matching the fields in each record (you have one record per line).

    Then count the lines and get the number of structs your array will need to be sized for, and then dynamically create the array of structs. That brings all the fields of a record, all together, and you only need one array, with one dimension, for everything.

    Since a sorted list is always better, I'd sort the structs, by telephone number. That makes adding up the minutes for any number, from multiple records (calls), easy.

    I'll post up a little example using your sample input, later.

  3. #3
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    Well, I couldn't get this down as nicely as I was hoping I could.

    For input, I used your sample, and copied it over until I had a screenful (15 records). I named the file, phone.txt.

    All that remains is:

    1) Add up the sorted phone minutes or airtime, as long as the number is the same, for the total minutes or airtime for that phone number.

    2) Add the code for the output you want, from #1.

    Code:
    /* consolidates phone record data
    
    */
    
    #include <stdio.h>
    #include <stdlib.h>
    
    struct phone_def {
      char date[9];
      char location[50];
      char time[9];
      char number[15];
      char type[3];
      char minutes[6];
      char airtime[3];
      char toll[5];
      char total[6];
      };
    typedef struct phone_def phone1;
    
    
    void mine(char *line1, phone1 *phone, int j);
    void sort(phone1 *phone, int n); 
    
    int main() {
      char line1[100]={'\0'};
      int i, n; 
      FILE *fp;
      phone1 *phone;
    
      if((fp=fopen("phone.txt", "rt")) == NULL) {
        printf(" error opening file - terminating\n");
        return 1;
      }
      n=0;
      while((fgets(line1, sizeof(line1), fp)) != NULL) 
        ++n;
      n-=3;
      printf("\n\nThere are %d records", n);
      rewind(fp);
      phone=malloc(sizeof(phone1) * n);
      if(phone==NULL) {
        printf("\n memory error - terminating\n");
        return 0;
      }
      for(i=0;i<3;i++)     //moves us past the header lines
        fgets(line1, sizeof(line1), fp); 
    
      for(i=0;i<n;i++)  {   //getting the records
        fgets(line1, sizeof(line1), fp); 
        printf("\n>> %s", line1);
        mine(line1, phone, i);
      }
    
      sort(phone, n);
      printf("\n\n Phone records, sorted by phone numbers: \n");
      for(i=0;i<n;i++) { 
        printf("\n%2d) %s %s %s %s %s %s %s %s %s", i+1, phone[i].date,\
          phone[i].location, phone[i].time, phone[i].number, phone[i].type, \
          phone[i].minutes, phone[i].airtime, phone[i].toll, phone[i].total);
      }
      printf("\n\n\t\t\t     press enter when ready");
      fclose(fp);
      i = getchar(); ++i;
      return 0;
    }
    /* mines the file data into the array of structs */
    void mine(char line1[100], phone1 *phone, int j) {
      int i, k; 
      
      i=1;
      k=0;
      while(line1[i] !='"') {
        phone[j].date[k]=line1[i++];
        ++k;
      }
      phone[j].date[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].location[k]=line1[i++];
        ++k;
      }
      phone[j].location[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].time[k]=line1[i++];
        ++k;
      }
      phone[j].time[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].number[k]=line1[i++];
        ++k;
      }
      phone[j].number[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].type[k]=line1[i++];
        ++k;
      }
      phone[j].type[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].minutes[k]=line1[i++];
        ++k;
      }
      phone[j].minutes[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].airtime[k]=line1[i++];
        ++k;
      }
      phone[j].airtime[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].toll[k]=line1[i++];
        ++k;
      }
      phone[j].toll[k]='\0';
      i+=3;
      k=0;
      while(line1[i] !='"') {
        phone[j].total[k]=line1[i++];
        ++k;
      }
      phone[j].total[k]='\0';
      printf("%2d) %s %s %s %s %s %s %s %s %s", j+1, phone[j].date, \
        phone[j].location, phone[j].time, phone[j].number, phone[j].type, \
        phone[j].minutes, phone[j].airtime, phone[j].toll, phone[j].total); 
    }
    /* Sort the records, by phone number */
    void sort(phone1 *phone, int n) {  
      int i, j;
      phone1 temp;
    
      for(i=0;i<n-1;i++) {
        for(j=i+1;j<n;j++) {
          if((strcmp(phone[i].number, phone[j].number)) >0) {
            temp = phone[i];
            phone[i] = phone[j];
            phone[j] = temp;
          }
        }
      }
    }
    By no means is this tested code, so test it thoroughly.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 7
    Last Post: 02-02-2009, 07:27 AM
  2. Replies: 9
    Last Post: 12-08-2008, 10:27 AM
  3. Reading int's from file to array HELP plz
    By GARiMTO in forum C Programming
    Replies: 3
    Last Post: 12-14-2007, 06:12 AM
  4. reading a file into an array
    By dantegl36 in forum C Programming
    Replies: 11
    Last Post: 12-02-2006, 12:23 AM
  5. Reading from file and crashing
    By Night_Blade in forum C++ Programming
    Replies: 1
    Last Post: 09-25-2005, 02:09 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21