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