在C语言中,任何整型变量都可以用来表示字符。这意味着int
可以存储字符。但是,当我在程序中声明一些条件语句时,程序没有显示预期的结果。下面是我的程序:
#include <stdio.h>
#include <conio.h>
int main(void)
{
auto signed int a;
clrscr();
printf("enter character");
scanf("%c", &a);
switch(a)
{
case 'K':
printf("upper case");
break;
case 'k':
printf("lower case ");
break;
default:
printf("no match found");
break;
}
return 0;
}
这是我的程序。当我输入大写字母“K”时。但是输出是“没有找到匹配”,这是什么问题呢?
4条答案
按热度按时间azpvetkf1#
简短的回答是“是”。
int
可以存储char
的值。例如:将打印“是”。
您的代码由于其他原因无法工作。在这一行中:
您提供了一个指向未初始化的
signed int
的指针,该指针至少有2个字节宽,可能有4个字节宽,但%c
化选项需要一个指向char
的指针,该指针为1个字节宽。现代编译器应该警告过这种情况。因此,只有
a
的第一个字节被输入的字符填充,所以当你输入'K'时,a
的第一个字节将等于'K',但其余的字节将有一些未定义的值。因此,a
可能不等于'K'(如观察到的)。解决方法是将
a
初始化为0:但是,为
scanf()
中的字符格式说明符提供signed int
指针是未定义的行为,因此不建议这样做。1l5u6lss2#
是的,任何C的整数类型都可以存储字符值。但是你不能使用
scanf("%c")
将字符值读入任何整数类型,因为scanf("%c")
只能将字符值 * 读入char
类型的变量。但你可以用
与
(其中
a
是short
或int
或long
或其他),它会工作得很好。(Here,不过,使用
char
实际上会更差,因为虽然它看起来很有效,但它会搞砸getchar
向您发出EOF信号的能力。)li9yvcax3#
gcc --version
9.4.0来编写和测试这个答案。*如何摆脱过时的Turbo C,安装免费的现代操作系统和编译器
我建议你去找一台旧的二手电脑,免费安装一个现代的操作系统,比如Ubuntu 22.04 LTS(转到https://ubuntu.com/,点击顶部的“下载”;完整的安装说明在这里:https://ubuntu.com/tutorials/install-ubuntu-desktop#1-overview)。这个操作系统被世界上许多现代科技公司使用,并且可以给予你轻松访问gcc,一个现代编译器。
Ubuntu是一个功能强大的平台,现在用户非常友好,有很好的GUI界面,就像其他现代操作系统一样。随着你的成长,我鼓励你鼓励你的学校和老师完全放弃Turbo C,把所有的教学迁移到Ubuntu上,这也是一个 * 免费 * 和开源的现代操作系统,能够在现实生活中的专业环境中使用。现代代码。例如,在我过去工作过的两家科技公司,它一直是我工作电脑上的主要操作系统。我在家里的所有电脑上也使用它,包括小孩的电脑。它运行Chrome浏览器很好,配有LibreOffice文本编辑器、Shotcut视频编辑软件,内置编译器和开发工具,如
gcc
(用于C)和g++
(用于C++),Python,Bash,Java等。构建错误,修复
scanf()
中未定义的行为我尝试使用以下命令在gcc中编译你的程序:
我得到了这个错误:
我以前从来没有听说过
conio.h
,所以我在谷歌上搜索了一下,找到了this answer:conio.h标头是Turbo C特有的,它比最早的C标准早了几年。它包含DOS命令行特有的例程。这里经常使用的一个函数是
getch
,它允许一次阅读一个字符,而不必按Enter键。它还包含gotoxy
,它允许将光标放置在终端的特定位置一般来说,像这样与终端通信的方法是非常特定于操作系统的,因此每种方法都有自己的(通常是不可移植的)方式。
这与stdio. h中的函数形成对比,stdio. h中包含
printf
、scanf
和getchar
等函数,这些函数无论使用什么类型的控制台都可以工作。所以,听起来问题下面的评论说你正在使用过时的工具是正确的。你的学校没有使用好的、现代的工具,需要改变。几乎没有人再使用DOS了。很多人和高科技公司使用Linux。Windows和Mac更受欢迎。我建议你改用Linux。只在学校使用Turbo C,但是要意识到你可能被教导了各种过时和不好的做法,所以也要在网上研究一些东西,并在你去的时候试着学习正确的方法。
您可以在https://www.onlinegdb.com/上免费在线在64位Linux机器上编程,但这与自己安装Ubuntu不同。
好了,我清理了一下你的代码,去掉了不寻常的
auto signed
用法,用一个在Linux上工作的系统调用替换了你的clear screen命令,现在有了这个:test.c:
使用我的build命令可以产生更好更安全的输出,因为我使用的是
-Wall -Wextra -Werror
,它不会生成。我得到以下错误。下面是build命令和错误:因此,要修复它,请将
int a;
替换为char a;
,并使用scanf()
的返回值来检查错误。输出示例:
根据C标准,使用
int a;
而不是char a;
是 undefined behavior,这意味着它是一个bug。更进一步:endianness检测,打印
int
中的所有字节并找到k
我对@neilsen的答案投了赞成票。它是正确的。让我们更深入地了解一下,当你使用
int a;
而不是char a;
时,会发生什么。注意:这是 undefined behavior,意思是C标准没有定义它,所以这是一个bug,我将要做的是编译器和计算机体系结构特定的。为了强制它编译,我将从构建命令中删除-Werror
。以下是我的新build命令:
这是我的新程序。我删除了
clear
调用,所以我们仍然可以看到编译器输出警告我们错误使用scanf()
:现在,这里是一个示例运行输出。注意我现在得到“No match found”:
让我们看看
int a
里面有多少字节。新程序:我在switch
语句后添加了print_bytes_in_variable()
函数和一些东西,包括endianness检测:样品运行和输出:
还有
k
!ASCII表显示k
是十六进制6B
,您可以在上面打印的第一个(在我的情况下是最低有效位)字节中看到这一点!然而,在此之后的其他值是垃圾(未定义)值,它们在运行此程序之前就位于我的内存中。要简单地将它们全部写入0来解决这个问题,请将
int a;
更改为int a = 0;
,现在您的程序可以工作了!再次运行它,您将看到:所以,* 它工作 *,是的,但是编译器警告仍然存在,并且程序仍然依赖于
scanf()
中的 * 未定义行为 *,所以即使 * 它按预期工作,它仍然有bug和 * 损坏 。 奇怪,是吧?嗯,就是这样。我们依赖于 * 可预测 *(对于我的编译器和计算机硬件)但是 undefined 行为(根据C标准),让我的程序“工作”。虽然它被破坏了。修复编译器警告。添加-Werror
回来把警告变成错误,并使用char a;
而不是int a;
来修复scanf()
中的未定义行为。结束。
参考文献
kpbwa7wx4#
根据你的代码,你已经将变量a声明为int,所以当你在输入时插入任何字符时,它将分配该字符的ASCII值,所以你需要将变量的数据类型从int更改为char。