0

I am getting a segmentation fault when I call my getField(char *line, int field) function in my while loop and I'm not sure why. I'm trying to pass a line to the function and a column number so that I can grab specific columns from each line in a csv file and print them to the screen. Thanks for input.

void getField(char *line, int field);

int main(int argc, char *argv[]) {

  if(argc < 3) {
    fprintf(stderr, "Too few arguments \"%s\".\n", argv[0]);
  }

  if(atoi(argv[1]) < 1) {
    fprintf(stderr, "First argument must be >= 1 \"%s\".\n", argv[1]);
  }
  FILE *fp = fopen(argv[2], "r");
  if(fp == NULL)
    fprintf(stderr, "Cannot open file %s\n", argv[0]);
  char buf[80];
  while(fgets(buf, 80, fp) != NULL) {
    getField(buf, atoi(argv[1]);  // seg fault is happening here
  }

  return 0;
}

void getField(char *line, int field) {
  printf("here2");
  //char *ln = line;
  int column = field - 1;
  int idx = 0;
  while(column) {
    //printf("here");
    if(line[idx] == ',') field--;
    idx++;
  }

  for(int j = idx; ; ++j) {
    if(line[j] == ',') break;
    printf("%s", line[j]);
  }
  printf("\n");
  printf("%d", idx);
}
7
  • Exactly which line is the segfault happening in? Commented Apr 16, 2014 at 5:45
  • Can you run gdb and post the backtrace for the seg fault? Commented Apr 16, 2014 at 5:46
  • 2
    In your 1st test you should stop the program, there is not point in continuing if there are not enough arguments. Commented Apr 16, 2014 at 5:46
  • @merlin2011 it's happening before the call to getField(). It's not even calling it. Commented Apr 16, 2014 at 5:48
  • 1
    In the while loop while(column) ... you are looping till column does not become zero. But you are never updating column. Commented Apr 16, 2014 at 5:48

4 Answers 4

4

One obvious error is that you have an infinite loop here, and you will eventually access illegal memory.

while(column) {
     //printf("here");
    if(line[idx] == ',') field--;
    idx++;
}

You are not modifying column at all, so your loop cannot possibly end. column will not update itself when you update field, so you will have to update it if you want it to update.

while(column) {
     //printf("here");
    if(line[idx] == ',') field--;
    idx++;
    column = field - 1;
}

Note on debugging segfaults using printf.

The function printf prints to stdout and stdout likes to buffer output. This means that sometimes if you try to find a segfault by moving a print statement down your code until it fails to print, you will misunderstand where the segfault it happening. In particular, a printf line that appears before the line that actually contains the segfault may not print even if you might expect it to.

If you want to use this strategy (instead of gdb), you can force it to print by using fflush(stdout); immediately after your debugging printf.

Sign up to request clarification or add additional context in comments.

3 Comments

Yeah, I used field-- instead of column-- by mistake. Why isn't the first printf("here") function being called in the first line of my getField function?
Because printf prints to stdout and stdout likes to buffer output. You can force it to print by using fflush(stdout).
Interesting.. I did not know that. Thank you very much for the help. I was able to fix the problem.
1
while(column) {
        //printf("here");
        if(line[idx] == ',') column--;  // Changed field-- to column--
                idx++;
}

Comments

0

In following line:

printf("%s", line[j]);

you are using the %s format specifier but you are passing a char as argument.

You probably want this (%c format specifier fot printing a char):

printf("%c", line[j]);

1 Comment

Yeah, that was one of the problems. I appreciate it. Thanks.
0

You are accessing out of bounds of the array in the function getField because the while loop never exits. This invokes undefined behaviour and most likely program crash due to segfault which is what is happening in your case. I suggest the following changes to your program.

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

void getField(char *line, int field);

int main(int argc, char *argv[]) {
  if(argc < 3) {
    fprintf(stderr, "Too few arguments \"%s\".\n", argv[0]);
    return 1; // end the program
  }

  if(atoi(argv[1]) < 1) {
    fprintf(stderr, "First argument must be >= 1 \"%s\".\n", argv[1]);
    return 1; // end the program
  }

  FILE *fp = fopen(argv[2], "r");
  if(fp == NULL) {
    fprintf(stderr, "Cannot open file %s\n", argv[0]);
    return 1; // end the program
  }

  char buf[80];
  while(fgets(buf, 80, fp) != NULL) {
    getField(buf, atoi(argv[1]));  // seg fault is happening here
  }

  return 0;
}

void getField(char *line, int field) {
  int len = strlen(line);
  char temp[len + 1];
  strcpy(temp, line);

  int count = 0;
  char ch = ',';
  char *p = temp;
  char *q = NULL;
  while(count < field - 1) {
    q = strchr(p, ch);
    if(q == NULL) {
      printf("error in the value of field\n");
      return;
    }
    count++;
    p = q + 1;
  }
  q = strchr(p, ch);
  if(q != NULL)
    *q = '\0';
  else 
    temp[len-1] = '\0';

  printf("%s\n", p);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.