我正在使用fscanf解析文本(css)文件。基本目标很简单;我想找出与此模式匹配的任何内容:
@导入“some/file/somewhere.css”;
所以我使用了fscanf,告诉它读取并丢弃最长为“@”字符的所有内容,然后将所有内容存储到“;”字符。下面是执行此操作的函数:
char* readDelimitedSectionAsChar(FILE *file)
{
char buffer[4096];
int charsRead;
do
{
fscanf(file, "%*[^@] %[^;]", buffer, &charsRead);
} while(charsRead == 4095);
char *ptr = buffer;
return ptr;
}
我已经创建了一个缓冲区,据我所知,它应该可以容纳4095个字符。然而,我发现事实并非如此。如果我有一个包含长字符串的文件,如下所示:
@导入“some/really/really/really/long/file/path/to/a/file”;
使用char[4096]缓冲区将其截断为31个字符。(如果我使用printf检查buffer的值,就会发现字符串被截断了。)
如果我增加缓冲区大小,则包含更多字符串。我的印象是一个字符占用一个字节(尽管我知道这是受编码影响的)。我想知道这里发生了什么。
理想情况下,我希望能够将缓冲区设置为需要的“动态”大小——也就是说,让fscanf创建一个足够大的缓冲区来存储字符串。能做到吗?(我知道GNU的%标志,但这是一个用于OS 10.5/10.6的Mac应用程序,我不确定这是否适用于这个平台。)
最佳答案
您的主要问题是返回一个指向堆栈上的本地缓冲区的指针,该缓冲区处于悬挂状态(因此在下次调用时会被覆盖)。您还可能有缓冲区溢出。
您提到了“a”选项,这将有很大帮助,但不幸的是,它是一个GNU扩展,通常不可用。
其次,您有这个额外的scanf选项,&charsRead
将永远不会被写入,因为格式字符串中没有它的%
。所以charsRead总是随机垃圾——这意味着循环(可能)只运行一次,或者(很少)永远循环。试试像这样的
char* readDelimitedSectionAsChar(FILE *file)
{
char buffer[4096], term[2] = "", *rv = 0;
int len = 0;
fscanf(file, "%*[^@]");
while (term[0] != ';' && !feof(file)) {
if (fscanf(file, "%4095[^;]%1[;]", buffer, term) > 0) {
int read = strlen(buffer);
rv = rv ? realloc(rv, len+read+1) : malloc(read+1);
strcpy(rv+len, buffer);
len += read;
}
}
return rv;
}
这个问题仍然存在,因为如果内存不足,它会出现错误行为(如果您将一个巨大的格式错误的文件以@开头,而不是;,则很容易发生这种情况),