c - 0 <= -1 怎么可能返回 true?
问题描述
我写了一个小程序作为例子来复制我遇到的问题。该程序以这种方式获取并操作两行:
- 它用新行分隔行。
- 每行包含一些字母,后跟一个空格(在本例中为
' '
),后跟一个数字。 - 它将字母复制到另一个字符串,然后添加
'\0'
到它。 - 它将数字复制到另一个字符。
- 它打印其中是复制的字母和 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 循环(这也是因为我们结束了line
with line[j] = '\0'
)。这也意味着j+1
应该是一个数字,它是行中的最后一个字符。如果不是这样,我们到达了不在数字之前的空白处,所以我们退出了函数。
那么,问题出在哪里?
read(char *text)
如您所见,我将两个字符串传递给函数。read(char *text)
完美地操作和打印第一个字符串。对于第二个,即 only "\n"
,该功能不能很好地工作。我不明白的部分是我们进入了 while 循环,尽管 conditionj <= strlen(line) - 1)
以某种方式返回1
when text = "\n"
。您可以看到,通过运行程序,它会在第 26 行打印该信息。
解决方案
在strlen(line) - 1
中, 的类型strlen(line)
为size_t
,无符号整数类型。size_t
在您的编译平台上定义, C 的提升规则使减法成为size_t
(无符号)减法,给出size_t
(无符号)结果。结果是(size_t)-1
,通常是0xffffffff
或0xffffffffffffffff
。
虽然没有提供上述解释,但这个在线 C 解释器通过指示您传递的格式错误类型来暗示%ld
问题printf
。在选定的编译平台上,上述适用且printf
参数strlen(line) - 1
类型为size_t
,应使用 打印%zu
。
此无符号算术导致您的程序在此内存位置未初始化时使用。 line[j]
如果您更改所有出现的strlen(line) - 1
to (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
。
推荐阅读
- json - 如何从 json ds_map 中找到值?
- apache-kafka - kafka 分区再平衡
- javascript - addEventListener:点击并移除标签
- rust - 如何使用对 FnOnce 闭包的引用?
- mysql - CRUD notes - 为笔记离线创建 ID
- java - 如何让 Discord Bot 等待特定用户使用 JDA 发送消息?
- java - 从另一个类访问正在运行的应用程序类
- c# - 正则表达式匹配基本路径
- mysql - MySQL - 用第 2 行的第 2 列减去第 1 行的第 1 列
- excel - 无法将剪贴板中的数据范围粘贴到其他工作簿的选定单元格