C:fscanf和字符/字符串大小

时间:2010-09-25 00:09:14

标签: c cocoa macos unix gnu

我正在使用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应用程序,我不确定它是否可以在这个平台上运行。)

2 个答案:

答案 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可能不适合这项工作。我会尝试getcfgets

char *readDelimitedSectionAsChar(char *buf, size_t n, char firstChar, char lastChar, FILE *f);