代码之家  ›  专栏  ›  技术社区  ›  Hanlon

0<=-1怎么可能返回true?[副本]

c
  •  0
  • Hanlon  · 技术社区  · 6 年前

    我写了一个小程序作为例子来复制我遇到的问题。程序以这种方式获取并处理两行:

    1. 它用新线把线分开。
    2. 每行由一些字母组成,后跟一个空格(在本例中 ' '
    3. 它将字母复制到另一个字符串中,然后添加 '\0' 去吧。
    4. 它将数字复制到另一个字符。

    这是最简单的程序:

    #include <stdio.h>
    #include <string.h>
    
    void read(char *text)
    {
        // create and initialize the line holder
        int k = 0;
        char line[10];
        line[0] = '\0';
        for (int i = 0;text[i] != '\0';i++)
        {
            if (text[i] == '\n')
            {
                // k now points to the character right after the last assigned one, so put 0 in that place
                line[k] = '\0';
    
                // initialize data objects that will hold text and number
                char letters[5];
                letters[0] = '\0';
                char val;
    
                // step through the line, and stop if you 1. reached a blank or 2. reached the end of a line
                int j = 0;
                while (line[j] != ' ' && line[j] != '\t' && j <= (strlen(line) - 1))
                {
                    printf("%d <= %ld = %d\n", j, strlen(line) - 1, j <= (strlen(line) - 1));
                    if (j == (strlen(line) - 1)) // reached the last character before reaching blank
                        return;
                    letters[j] = line[j];
                    j++;
                }
    
                letters[j] = '\0'; // where should be blank place 0
    
                if (j + 1 == (strlen(line) - 1)) // if the next character is the last character, meaning that the character before the last one is blank
                    val = line[j + 1];
                else // there is space in that is not one before the last character
                    return; // this is where read("\n") should stop, but withou entering the while loop!
    
                printf("Word: %s\tVal: %d\n", letters, val - '0');
    
                // empty the line holder
                line[0] = '\0';
                k = 0;
            }
            else
            {
                // place the ith text character into the kth line character and print them
                line[k] = text[i];
                printf("line[k] = %c\ttext[i] = %c\n", line[k], text[i]);
    
                // increment k for the next turn
                k++;
            }
        }
    }
    
    int main()
    {
        char *text = "ABCD 0\nEFGH 1\nIJKL 2\nMNOP 3\nQRST 4\nUVWX 5\nYZ 5\n";
        read(text);
        printf("---------------------------------\n");
        read("\n");
        return 0;
    }
    

    return 关键字和注释 read(char *text)

    第28行: '\t' ).

    第38行: 如果我们成功退出while循环,角色 j 是从 line 应该是空白。这是因为当我们发现一个空白时退出了while循环(这也是因为我们结束了 线 line[j] = '\0' ). 这也意味着 j+1 应该是一个数字,这是行中的最后一个字符。如果不是这样的话,我们到达了一个不在数字前面的空白,这样我们就退出了函数。


    那么,问题出在哪里?我把两条线传给 读取(字符*文本) 功能,如你所见。 读取(字符*文本) 完美地操纵和打印第一个字符串。第二个是 "\n" ,该函数没有那么好地工作。我不明白的是,我们进入while循环,不管条件如何 j <= strlen(line) - 1) 1 什么时候 text = "\n" . 您可以看到,通过运行程序,它会在第26行打印这些信息。
    2 回复  |  直到 6 年前
        1
  •  7
  •   Pascal Cuoq    6 年前

    strlen(line) - 1 ,类型 strlen(line) size_t ,一个无符号整数类型。定义为 大小\u t C's promotion rules 做减法 大小\u t 大小\u t (size_t)-1 ,这通常是 0xffffffff 0xffffffffffffffff .

    虽然没有提供上述解释, this online C interpreter 通过指示传递的格式类型错误来提示问题 %ld 在里面 printf 论点 斯特伦(线路)-1 有类型 ,应该用 %zu .

    此无符号算术导致程序 use line[j] 斯特伦(线路)-1 (int)strlen(line) - 1 ,强制 int the program does not have undefined behavior .

    如评论中所述,改变 斯特伦(线) (int)strlen(line) 只是一个快速而肮脏的修复,并且限制了程序可以应用于的输入范围 比…窄 大小\u t strlen 并重写它,使之符合程序员的意图 大小\u t j == (strlen(line) - 1) 可以写 (size_t)j + 1 == strlen(line) . 这反过来又表明,许多变量,包括 j 大小\u t 而不是 内景

        2
  •  4
  •   klutt    6 年前

    $ clang -Wall -Wextra -std=c11 -pedantic-errors k.c
    k.c:24:59: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
                while (line[j] != ' ' && line[j] != '\t' && j <= (strlen(line) - 1))
                                                            ~ ^   ~~~~~~~~~~~~~~~~
    k.c:26:67: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
                    printf("%d <= %ld = %d\n", j, strlen(line) - 1, j <= (strlen(line) - 1));
                                                                    ~ ^   ~~~~~~~~~~~~~~~~
    k.c:27:23: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
                    if (j == (strlen(line) - 1)) // reached the last character before reaching blank
                        ~ ^   ~~~~~~~~~~~~~~~~
    k.c:35:23: warning: comparison of integers of different signs: 'int' and 'unsigned long' [-Wsign-compare]
                if (j + 1 == (strlen(line) - 1)) // if the next character is the last character, meaning that t...
                    ~~~~~ ^   ~~~~~~~~~~~~~~~~
    4 warnings generated.
    

    比较有符号和无符号确实是这里的问题。

    j == (strlen(line) (size_t)j == (strlen(line) 但后者不会产生警告。