使用C动态存储文件中的信息

使用C动态存储文件中的信息,c,pointers,char,realloc,memset,C,Pointers,Char,Realloc,Memset,我是C语言的新手,正在努力学习一些东西。我要做的是读入一个文件并存储信息。由于格式为CSV,计划是读取每个字符,确定其是数字还是逗号,并将数字存储在链接列表中。我遇到的问题是读取长度超过一个字符的数字,如下面的示例所示 5,2,24,5 这是我到目前为止得到的代码,它没有返回我所期望的输出。这是代码,输出在代码示例下面 #include <ctype.h> #include <stdio.h> #include <string.h> #include <

我是C语言的新手,正在努力学习一些东西。我要做的是读入一个文件并存储信息。由于格式为CSV,计划是读取每个字符,确定其是数字还是逗号,并将数字存储在链接列表中。我遇到的问题是读取长度超过一个字符的数字,如下面的示例所示

5,2,24,5

这是我到目前为止得到的代码,它没有返回我所期望的输出。这是代码,输出在代码示例下面

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

struct list {
  float value;
  struct list * next;
  struct list * prev;
};

int main( int argc, char *argv[] ){
  FILE *infile;
  char *token = NULL;
  char  my_char;

  /* Open the file. */
  // The file name should be in argv[1]
  if((infile = fopen(argv[1], "r")) == NULL) {
    printf("Error Opening File.\n");
    printf("ERROR: %s\n", strerror(errno));
    exit(1);
  }

  while((my_char = (char)fgetc(infile)) != EOF){
    //Is my_char a number?
    if(isdigit(my_char)){
      if(token == NULL){
        token = (char *)malloc(sizeof(char));
        memset(token, '\0', 1);
        strcpy(token, &my_char);
        printf("length of token -> %d\n", strlen(token));
        printf("%c\n", *token);
      } else {
        token = (char *)realloc(token, sizeof(token) + 1);
        strcat(token, &my_char);
        printf("%s\n", token);
      }
    }
  }

  free(token);
  fclose(infile);
}
我不明白为什么当我希望标记的长度为1时,标记的长度为“5”,而后面的字符看起来很奇怪(由“a#”表示)。有人能帮我更好地理解这一点吗

char *token = NULL;

token = (char *)realloc(token, sizeof(token) + 1);
token
是一个指针
sizeof
不会给出它所指向的内存块的分配大小;它提供指针对象本身的大小。显然,系统上的指针是4个字节(这是典型的),所以您总是要重新分配到5个字节

还有一些建议:

exit(1);
退出(退出失败)
更便于携带

char my_char

while((my_char = (char)fgetc(infile)) != EOF){
fgetc
返回整数,而不是字符。该值是从文件读取的下一个字符(表示为无符号字符,然后转换为int,因此通常在0..255范围内)或值
EOF
(通常为-1)。如果在系统上对纯字符进行了签名,则恰好为255的输入字符将导致循环提前终止;如果纯字符是无符号的,循环可能永远不会结束,因为您正在将
EOF
的负值转换为有符号值。事实上,我不是100%确定后一种情况会发生什么,但这并不重要;将
my_char
设为int

token = (char *)malloc(sizeof(char));
不要强制转换
malloc()
的结果。它不是必需的(
malloc()
返回一个
void*
,因此可以隐式转换),并且可以隐藏错误
sizeof(char)
定义为1。只要写下:

token = malloc(1);
并始终检查返回值
malloc()
失败时返回NULL

memset(token, '\0', 1);
更简单:
*令牌='\0'

分配一个字节,然后
realloc()

strcat(token, &my_char);
strcat()
的第二个参数必须是指向字符串的指针
&my_char
的类型正确,但如果内存中
my_char
后面的字节不是“
\0”
可能会发生不好的事情

这不是一个详尽的审查


推荐阅读:.

主要问题似乎是以null结尾的字符串存在问题。
malloc
调用正在分配1个字节。但是strcpy复制字节,直到它到达一个空终止符(零字节)。因此,由于
my_char
之后的字节是堆栈中的“随机”值,因此结果没有得到很好的定义

您需要分配比字符串长度长一个字节(realloc长一个字节),以允许空终止符。并且
strcpy
strcat
调用对于实际上只是一个字符的源“字符串”无效。要继续使用您正在实现的基本逻辑,只需将字符值分配到
标记
数组中的适当位置即可。或者,您可以将
my_char
声明为双字节字符数组,并将第二个字节设置为0终止符,以允许使用
strcpy
strcat
。比如说,

char my_char[2];
my_char[1] = '\0';

然后需要相应地更改
my_char
的用法(将值分配给
my_char[0]
,并删除strcpy/strcat调用中的
&
)。编译器警告/错误将有助于解决这些更改。

您在代码中只为字符串分配了1字节的数据:

token = (char *)malloc(sizeof(char));
memset(token, '\0', 1);
token = (char *)malloc(sizeof(char));

然而,因为您只将一个字节归零,所以字符串不一定以null结尾。你最有可能看到的是在你的char*

之后内存中的额外垃圾。首先,一次读一整行比一次读一个字符要容易得多。然后可以使用
strtok()
以逗号分隔行

您的代码存在一些问题:

token = (char *)malloc(sizeof(char));
memset(token, '\0', 1);
token = (char *)malloc(sizeof(char));
这将只分配1个字节。C字符串必须以null结尾,因此即使长度为1的字符串也需要2字节的分配空间

strcpy(token, &my_char);
strcat(token, &my_char);
my_char
是单个字符,而不是以null结尾的字符串(这是
strcpy()
strcat()
所期望的)


这不是你想做的。这将返回指针的大小(即
标记的类型)。您可能需要类似
strlen()的内容
,但您必须重构代码,以确保使用以null结尾的字符串,而不是单个字符。

您的
my_char
应该是
int
,因为这是返回的结果,使用
char
将意味着您永远找不到EOF条件:

int my_char;
/*...*/
while((my_char = fgetc(infile)) != EOF) {
EOF
值是一个无效的
int
字符,这就是在每次读取一个字节并从以下位置读取文件时检测文件结尾的方式:

如果fgetc()返回的整数值存储在char类型的变量中,然后与整型常量EOF进行比较,则比较可能永远不会成功,因为char类型变量在加宽为整数时的符号扩展是由实现定义的

其他人已经指出了你的记忆错误,所以我不谈这些

while((my_char = (char)fgetc(infile)) != EOF){
这是一个糟糕的时刻。
fgetc
返回
int
。它可以表示比
char
更多的值
EOF
通常是
-1
。既然您存储在
char
中,您如何
int c;

while ((c=fgetc(infile)) != EOF)
{
   char my_char = c;
       token = (char *)malloc(sizeof(char));
       memset(token, '\0', 1);
       strcpy(token, &my_char);
token[0] = my_char;
token[1] = 0;
       token = (char *)realloc(token, sizeof(token) + 1);
 void *ptr = realloc(token, new_length);
 if (!ptr) { /* TODO: handle error */ }
 token = ptr;
       strcat(token, &my_char);
int c;
size_t alloc_size = 0;
size_t current_len = 0;
char *token = NULL;
void *ptr;

while ((c = fgetc(infile)) != EOF)
{
   if (is_digit(c))
   {
      if (alloc_size < current_len + 2)
      {
         if (!alloc_size)
         {
            // Set some arbitrary start size...
            //
            alloc_size = 64;
         }
         else
         {
            alloc_size *= 2;
         }

         if (!token)
            ptr = malloc(alloc_size);
         else
            ptr = realloc(token, alloc_size);

         if (!ptr)
         {
            free(token);
            return -1;
         }
      }

      token[current_len++] = c;
      token[current_len] = 0;
   }
}

/* TODO: do something with token... */

free(token);
while(*dest++ = *src++);