【问题标题】:Weird behavior counting lines from a file奇怪的行为计数文件中的行
【发布时间】:2012-02-21 21:06:13
【问题描述】:

寻找一种从配置文件中读取参数的方法我找到了一种很好的方法,但问题是当我尝试计算行数时会发生一些非常奇怪的事情。

这是代码:

FILE *file = fopen("config", "r");

char line[100];
int linenum = 0;
//int foo;  Uncomment and it starts to working, doesn't matter if you rename it.

while(fgets(line, sizeof(line), file) != NULL) {
    char option[4];
    char arg[100];

    if (line[linenum] == '#') 
        continue;
    linenum++;

    if (sscanf(line, "%s %s", option, arg) != 2)
        fprintf(stderr, "Syntax error, line %i\n", linenum);

配置文件如下所示:

#config file
option1
option2
option3

所以结果是:

Syntax error, line 1
Syntax error, line 0
Syntax error, line 0

但是,如果我在 while 循环之前声明一个具有任何名称的 int 变量,它就会开始工作!

结果是:

Syntax error, line 1
Syntax error, line 2
Syntax error, line 3

这里到底发生了什么?我的脑子要炸了,也许这很愚蠢,但我看不出有什么原因。

【问题讨论】:

  • 不应该是你的问题,但你不想检查line[0] == '#'而不是line[linenum]吗?
  • 你说得对,我刚刚将 line[linenum] 更改为 line[0] 非常感谢。

标签: c algorithm file gcc


【解决方案1】:

您的 option 数组太小 (char option[4]),因此 sscanf 会覆盖其他内容。未定义的行为。

通常,当奇怪的事情无缘无故发生时(比如在你声明一个不相关的变量之前“工作”的事情),这是因为内存问题。既然你提到了gcc,你可能想看看valgrind

【讨论】:

  • 哇,非常感谢,我现在感觉很愚蠢我已经为此奋斗了好几个小时,我对 c 如何与内存一起工作的理解有点差,我现在正在检查 valgrind。顺便说一句,您知道防止 sscanf 覆盖其他内容的方法吗?
  • @gmol 使用安全格式说明符。增加option 的大小。例如char option[20],然后在 sscanf 中使用%19s 而不是%s
  • 好的,这就是我要做的。非常感谢您的帮助。
【解决方案2】:

至少看起来像这部分:

if (line[linenum] == '#') continue;
  linenum++;

由于您在行首检查注释字符,因此不会给出所需的结果。

【讨论】:

    【解决方案3】:

    任何时候你看到这样的奇怪行为,你应该开始寻找内存溢出错误。典型症状包括:

    1. 如果您添加或删除未使用的变量,代码会运行或停止运行。
    2. 无明显原因发生变化的变量。
    3. 使用相同输入的代码有时会正常运行,有时会崩溃。
    4. 使用相同输入在调用之间产生不同结果的代码。

    在这种情况下,正如其他答案所指出的那样,您有两个潜在的与内存相关的错误:

    在线if (line[linenum] == '#') continue;

    应该是if (line[0] == '#') continue;

    否则linenum > 99时索引无效。

    还有if (sscanf(line, "%s %s", option, arg) != 2){这一行

    如果输入字符串太长,将超出optionarg 变量。 (您看到的错误是因为文本(例如 option1)超过 4 个字符并溢出 option。您可以通过多种方式解决此问题:

    • 增加option 的大小。您需要知道输入字符串的最大长度才能选择合适的大小。
    • 限制复制到option的字符数:
      if (sscanf(line, "%3s %99s", option, arg) != 2){
      这可能会导致长输入字符串出现意外输出,因为如果arg 被截断,option 将包含字符串的其余部分。
    • 根据http://linux.die.net/man/3/sscanf,您可以使用a 修饰符告诉sscanf 在读取字符串时为字符串分配内存:
      char **str1, **str2;
      if (sscanf(line, "%as %as", &str1, &str2) != 2){

    【讨论】:

    • 非常感谢,非常感谢您花时间检查并解释代码中的错误,顺便说一句,解释得很好。
    【解决方案4】:
    if (sscanf(line, "%s %s", option, arg) != 2)
    

    这会溢出option 数组并将覆盖linenum 对象。

    【讨论】:

      猜你喜欢
      • 2018-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-08
      • 1970-01-01
      • 2013-11-27
      • 1970-01-01
      相关资源
      最近更新 更多