2010-09-25 60 views
0

我使用fscanf解析文本(css)文件。基本目标很简单;我想提取任何符合此模式的内容:C:fscanf和字符/字符串大小

@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

你的主要问题是,你的堆栈,它晃来晃去(和你进行下一次调用,这样覆盖)上返回一个指针到本地缓存。你也有潜在的缓冲区溢出。 您提到'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

您的缓冲区是本地函数。您为其指定一个指针,但当调用者访问指针时,缓冲区不再存在。任何事情都可能发生。

所以,不要那样做。

scanf可能不是正确的工具。我会尝试getcfgets

char *readDelimitedSectionAsChar(char *buf, size_t n, char firstChar, char lastChar, FILE *f); 
相关问题