【问题标题】:Segmentation fault when passing pointer to function将指针传递给函数时出现分段错误
【发布时间】:2014-04-16 05:41:25
【问题描述】:

当我在 while 循环中调用 getField(char *line, int field) 函数时遇到分段错误,我不知道为什么。我正在尝试将一行传递给函数和一个列号,以便我可以从 csv 文件中的每一行中获取特定列并将它们打印到屏幕上。感谢您的意见。

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

【问题讨论】:

  • 段错误发生在哪一行?
  • 你能运行 gdb 并发布 seg 错误的回溯吗?
  • 在您的第一次测试中,您应该停止程序,如果没有足够的参数,则继续没有意义。
  • @merlin2011 它发生在调用 getField() 之前。它甚至没有调用它。
  • 在 while 循环 while(column) ... 中循环直到 column 不为零。但是你永远不会更新column

标签: c


【解决方案1】:

一个明显的错误是你这里有一个无限循环,你最终会访问非法内存。

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

您根本没有修改column,因此您的循环不可能结束。 column 不会在您更新 field 时自行更新,因此如果您希望它更新,则必须对其进行更新。

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

使用printf调试段错误的注意事项。

函数printf 打印到stdoutstdout 喜欢缓冲输出。这意味着有时如果您试图通过将打印语句向下移动代码直到它无法打印来查找段错误,您会误解它发生的段错误。特别是,出现在实际包含段错误的行之前的 printf 行可能不会打印,即使您可能希望它打印。

如果您想使用此策略(而不是gdb),您可以在调试printf 后立即使用fflush(stdout); 强制它打印。

【讨论】:

  • 是的,我错误地使用了字段而不是列。为什么我的 getField 函数的第一行没有调用第一个 printf("here") 函数?
  • 因为printf 打印到stdoutstdout 喜欢缓冲输出。您可以使用fflush(stdout) 强制它打印。
  • 有趣..我不知道。非常感谢你的帮助。我能够解决问题。
【解决方案2】:
while(column) {
        //printf("here");
        if(line[idx] == ',') column--;  // Changed field-- to column--
                idx++;
}

【讨论】:

    【解决方案3】:

    在下一行:

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

    您正在使用 %s 格式说明符,但您将 char 作为参数传递。

    您可能想要这个(%c 格式说明符用于打印 char):

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

    【讨论】:

    • 是的,这是问题之一。我很感激。谢谢。
    【解决方案4】:

    您正在访问函数getField 中的数组边界外,因为while 循环永远不会退出。这会调用未定义的行为,并且很可能由于段错误而导致程序崩溃,这就是您的情况。我建议对您的程序进行以下更改。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-05
      • 2014-12-10
      相关资源
      最近更新 更多