细分错误,但找不到

时间:2019-01-15 13:12:13

标签: c csv

我被困住了,因为我不明白为什么我的解析器代码无法正常工作,一个编译器只是说分段错误。虽然其他编译器会对其进行编译,但它只会返回错误代码

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

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

int
main ()
{
  FILE *stream = fopen ("input", "r");
  FILE *fp;
  char line[1024];
  while (fgets (line, 1024, stream))
  {
     char *tmp = strdup (line);
     char buf[0x100];
     snprintf (buf, sizeof (buf), "c:\\temp\\%s.txt", getfield (tmp, 1));
     fp = fopen (buf, "w");
     int count = 0;
     while ((tmp = strchr (tmp, ',')) != NULL)
     {
       count++;
       tmp++;
     }
     if (count == 4 ){
       fprintf (fp,
               "{This is my name %s\n I'm %s years old\n my       useragent is %s\n My hobbies are %s\n}",
               getfield (tmp, 1), getfield (tmp, 2),
               getfield (tmp, 4), getfield (tmp, 5));
     }
     else {
        fprintf (fp,
                 "{This is my name %s\n I'm %s years old\n my       useragent is %s%s\n My hobbies are %s\n}",
                 getfield (tmp, 1), getfield (tmp, 2),
                 getfield (tmp, 4), getfield (tmp, 5),
                 getfield (tmp, 6));
     }

     fclose (fp);
     free (tmp);
   }
}

我有一个包含数千行的csv文件。例子

Name,age,gender,useragent,hobby
maximilian,16,Male,Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko,skateboard

我正在尝试为每个名称创建一个文件,并在其中添加其他信息。因此它将输出例如

maximilain.txt

This is my name maximilian
 I'm 16 years old
 my useragent is Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko
 My hobbies are skateboard

1 个答案:

答案 0 :(得分:0)

之后

while ((tmp = strchr (tmp, ',')) != NULL)
{
  count++;
  tmp++;
}

tmp 为NULL,因此对getfield的下一次调用将获得一个空指针, while 必须在另一个指针上完成,否则您需要在之前保存tmp < / p>

例如:

char * p = tmp;

while ((p = strchr (p, ',')) != NULL)
{
  count++;
  p++;
}

如前所述,您对 strtok 的使用是错误的,因为在每次调用后都会修改字符串。

您可以修改 getfield 以处理副本:

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

但这是一个糟糕的方法,因为每次必须去绕过越来越多的令牌时抛出字符串。

我让您优化代码以在每一行中仅提取一次令牌。


还请注意,您使用的是csv的第一行,因此您将基于“名称”等创建文件