我正在使用fscanf解析文本(css)文件。基本目标很简单;我想拉出符合这种模式的任何东西:
@import“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个字符,据我所知。但是,我发现事实并非如此。如果我有一个包含匹配字符串的文件很长,如下所示:
@import“some / really / really / really / long / file / path / to / a / file”;
使用char [4096]的缓冲区将其截断为31个字符。 (如果我使用printf检查缓冲区的值,我发现字符串被缩短了。)
如果我增加缓冲区大小,则包含更多字符串。我的印象是一个字符需要一个字节(虽然我知道这会受到编码的影响)。我想了解这里发生了什么。
理想情况下,我希望能够将缓冲区设置为需要“动态”的大小 - 也就是说,让fscanf创建一个足够大的缓冲区来存储字符串。可以这样做吗? (我知道%作为GNU的标志,但这是OS 10.5 / 10.6的Mac应用程序,我不确定它是否可以在这个平台上运行。)
答案 0 :(得分:2)
你遇到的主要问题是你正在返回一个指向堆栈上本地缓冲区的指针,这个指针是悬空的(并且会被你下次调用所覆盖)。您还有潜在的缓冲区溢出。 你提到'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;
}
如果你的内存不足会导致内存不足(如果你在开头提供一个带有@的巨大格式错误的文件并且没有;),那么它仍会被打破。
答案 1 :(得分:1)
您的缓冲区是函数的本地缓冲区。您为其指定了一个指针,但是当调用者访问指针时,缓冲区不再存在。任何事情都可能发生。
所以,不要这样做。
scanf
可能不适合这项工作。我会尝试getc
或fgets
。
char *readDelimitedSectionAsChar(char *buf, size_t n, char firstChar, char lastChar, FILE *f);