首页 > 解决方案 > 0 <= -1 怎么可能返回 true?

问题描述

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

  1. 它用新行分隔行。
  2. 每行包含一些字母,后跟一个空格(在本例中为' '),后跟一个数字。
  3. 它将字母复制到另一个字符串,然后添加'\0'到它。
  4. 它将数字复制到另一个字符。
  5. 它打印其中是复制的字母和 int 的字符串,其中是转换后的复制数字。

这是那个最小的程序:

#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 行:如果检测到当前字符是最后一个字符,程序将停止扫描此行。由于最后一个字符应该始终以空格开头,这意味着我们在没有退出 while 循环的情况下到达了行尾(如果我们到达' 'or就会发生这种情况'\t')。

第 38 行:如果我们成功退出了 while 循环,j则偏移的字符line应该是空白。那是因为我们在找到空白时退出了 while 循环(这也是因为我们结束了linewith line[j] = '\0')。这也意味着j+1应该是一个数字,它是行中的最后一个字符。如果不是这样,我们到达了不在数字之前的空白处,所以我们退出了函数。


那么,问题出在哪里?read(char *text)如您所见,我将两个字符串传递给函数。read(char *text)完美地操作和打印第一个字符串。对于第二个,即 only "\n",该功能不能很好地工作。我不明白的部分是我们进入了 while 循环,尽管 conditionj <= strlen(line) - 1)以某种方式返回1when text = "\n"。您可以看到,通过运行程序,它会在第 26 行打印该信息。

标签: c

解决方案


strlen(line) - 1中, 的类型strlen(line)size_t,无符号整数类型。size_t在您的编译平台上定义, C 的提升规则使减法成为size_t(无符号)减法,给出size_t(无符号)结果。结果是(size_t)-1,通常是0xffffffff0xffffffffffffffff

虽然没有提供上述解释,但这个在线 C 解释器通过指示您传递的格式错误类型来暗示%ld问题printf。在选定的编译平台上,上述适用且printf参数strlen(line) - 1类型为size_t,应使用 打印%zu

此无符号算术导致您的程序在此内存位置未初始化时使用。 line[j]如果您更改所有出现的strlen(line) - 1to (int)strlen(line) - 1,以强制int减法计算带符号的结果,则程序没有未定义的行为

正如评论中所指出的,更改strlen(line)(int)strlen(line)只是一个快速而肮脏的修复,并且限制了程序可以应用的输入范围 ifint窄于size_t. 正确的解决方法是检查每个涉及结果的较大表达式strlen并重写它,以便它使用size_t算术执行程序员的意图。例如,条件j == (strlen(line) - 1)可以写成(size_t)j + 1 == strlen(line)。这反过来表明许多变量,包括j,应该直接声明为size_t而不是int


推荐阅读