行业门户网站建设,北京网站建设 案例,企业网站代维护,受欢迎的商城网站建设赋值表达式 表达式是什么#xff1f;表达式是由运算符和操作数组成的式子。 如下的代码 #include iostream.h int main() { int a1,b2,sum; cout(sumab)endl; return 0; } 那么如下的呢#xff1f; #include iostream.h int mai… 赋值表达式 表达式是什么表达式是由运算符和操作数组成的式子。 如下的代码 #include iostream.h int main() { int a1,b2,sum; cout(sumab)endl; return 0; } 那么如下的呢 #include iostream.h int main() { int a1,b2; cout(int sumab)endl; return 0; } 结果是 编译就会出错 在这里这是声明和定义不能放置于cout输出的位置。 sizeof运算符 C语言中提供了一个可以得到各种数据类型占用内存空间大小的运算符 sizeof运算符。 它的语法如下sizeof(类型名或变量名) 如下 #includeiostream using namespace std; int main() { coutsizeof(int)endl; return 0; } 在32位机器上就会打印4. 在16位机器上就会打印2. 如果想要得到所有基本类型占用的字节数如下代码 #include iostream #includeconio.h using namespace std; int main() { coutIt will show the lengths of all kinds of numbers(It is system-related):endl; coutchar ---------------sizeof(char)endl; coutbool ---------------sizeof(bool)endlendl; coutunsigned char ------sizeof(unsigned char)endl; coutwchar_t ------------sizeof(wchar_t)endl; coutshort --------------sizeof(short)endl; coutunsigned short -----sizeof(unsigned short)endlendl; coutint ----------------sizeof(int)endl; coutunsigned int -------sizeof(unsigned int)endl; coutlong ---------------sizeof(long)endl; coutunsigned long ------sizeof(unsigned long)endl; coutfloat --------------sizeof(float)endl; coutdouble -------------sizeof(double)endlendl; getch(); return 0; } 此程序是得到了各种不同的数据类型或者称作基本数据类型或内置数据类型在内存中占据的空间。请不要相信这些类型占用空间一定是如上图示因为它们是具有系统依赖性的不同的系统可能不一样的。 类型不一致带来的问题 #include iostream.h int main() { int i; cini; coutiendl; return 0; } 这个程序声明的i是整型而实际上如果输入了浮点类型的数如1.2那么将打印什么呢 打印的是1. 原因很简单声明的int是整型的当遇到的输入符号不是整数0~9字符时就会认为输入结束。 我们用C风格代码来改写这个程序 #includestdio.h int main() { int i; scanf(%d,i); printf(%d\n,i); return 0; } 结果也是一样 下面是个关于用不同类型的值来赋值的例子 #include iostream.h int main() { int x10.4; coutxendl; return 0; } 编译的时候出现警告 意思就是10.4是个double类型常量现在要把它赋值给整型变量中可能有数据精度或数值的损失。 A其实x的值是在编译结束之前就已经计算出来了。 Q这个不该是程序执行的时候才算的吗 A其实编译器也是一种程序嘛这些事情编译器可以做了就不用麻烦CPU在这个程序执行的时候做了。C语言是高效率的程序设计语言一个很大的原因就在于有很多事情在编译的时候就可以计算好。 Q那么为什么编译器把10.4看成了double类型呢 A那你觉得还可以看成什么类型呢 Q不可以看成是float类型吗 A应该说float类型只是double类型的子集编译器也是为了考虑数据精度和数据能表达的范围来考虑一般对于之类数据都看成double类型统一处理。 A就是把整数10赋值给变量x的。 溢出 现在我们深入研究下程序设计语言中存在的溢出现象 下面这个程序是一个溢出的实例 #include iostream.h int main() { short h32768; couthendl; return 0; } short类型是16位的最大能表达的数据是32767而却给它赋值32768; 这将导致溢出溢出的结果是可能造成不可预料的错误一般都会出现错误。 当然溢出也有一定的规律可循 32767的表示为 0111 1111 1111 1111 而赋值32768就是在32767的基础上再加1得到 1000 0000 0000 0000, 当然计算机会把这个当作short类型处理是个负数-32768. 我们要熟记计算机内部各种数据类型的取值范围这样才能在应用的时候选择更好的数据类型而且也能最大程度地避免发生错误就算发生了错误也能在最快的时间理解错误可能发生的原因。 【C#的checked关键字】 C#中的checked关键字可以实现对于整型算术运算启用溢出检查。 当然这个关键字不能直接拿到C语言中来使用如果可以的话可以自己写个程序同样用来判断整型数据类型在计算中是否溢出。 【编译器是如何从源代码计算一个整数的值的】 正如上面的代码short h32768; 对于编译器来说源代码就是字符串的集合。如何把数字形式的字符串转换成整数这是编译器需要做的事情。 C中有atoi、atol等将字符串转换成整数或长整型的函数。 这两个函数在atox.c源文件中有具体实现的代码。 【如何得到一个溢出的数的准确值】 正如上面当把32768赋给一个short类型的变量时。首先先考虑short类型的最大和最小值。最大值是32767最小值是-32768. 再分析当前赋给此变量的值是多少。 是32768它和short类型的最大值差不多而且是比最大值要大。所以先得到32767的形式。 0111 1111 1111 1111 中间的空格仅仅是为了看起来更清楚 32768比32767大1即再加1. 得到 1000 0000 0000 0000 所以结果也就知道了。 【用C/C写的检测溢出程序】 /* 完成时间2008年8月10日14:51:57 作者 陈曦 作用概述此程序用于检测int、short、long类型数据的加法是否发生溢出运用的是双符号位原理 如果两个相加的数是符号相同但是得到的和的符号与它们的不相同那么这就发生了计算溢出。 程序的局限如果在输入两个要相加的数的时候输入的数就已经溢出了那么程序得到的结果可能就错了。 扩充性对于float等浮点类型没有进行过测试不知道此程序是否可以得到正确结果。 */ //头文件 #include iostream using namespace std; //数据类型的宏定义可以改为int、long类型 #define TYPE short //检测加法是否溢出的函数参数为TYPE类型的两变量 void checkAdd(TYPE i,TYPE j) { //定义要处理的三个数的符号初始化为0 int sign[3]{0}; //如果数大于等于0那么符号为0否则符号为1(用自增的方式体现) i0? sign[0] : sign[0]; j0? sign[1] : sign[1]; //定义相加的和sum TYPE sumij; //计算sum的符号 sum0? sign[2] : sign[2]; if(sign[0]0sign[1]0sign[2]1 //如果两加数为正数且和为负数 ||sign[0]1sign[1]1sign[2]0 )//如果两加数为负数且和为正数 //那么得出溢出的结论 { couti j sum ,sum is overflow!endl; } //否则没有溢出 else { couti j sumendl; } } //主函数 int main() { TYPE i,j; //输入两要相加的数的值 cinij; checkAdd(i,j); return 0; } 下面是个关于无符号类型数据溢出的实例 #include iostream.h int main() { unsigned short h65535; h1; couthendl; return 0; } 这个可以理解成溢出。 毕竟short类型长度是16位而最大也只能表达65535; 后面的一句加了1从二进制的角度考虑就是 1111 1111 1111 1111 0000 0000 0000 0001 0000 0000 0000 0000 最高位进位了但是却不会显示出来了。 有一天老师布置了一个较大的数相乘的题目当然懒得用笔算用程序吧。 #include iostream.h int main() { cout32767*32767*32767endl; return 0; } 显然答案是错的至少从尾数就可以判断出来。 那么哪错了呢 溢出。 Q那么为什么编译器不把这个值看做是double类型的呢如果是这样不就不会溢出了吗 A当然编译器没这么聪明。当代码中是整数字面值出现的时候编译器就认为结果也是用整型表示的。所以也就溢出了。 【操作符中间有空格】 实际上考虑这个问题得从这个角度去想标识符和操作符其实在这一点上等同看待即标识符中间不能有空格那么操作符也不可以。 还有很多类似情况 #include iostream.h int main() { int a10; if(a 1) coutIt is bigger than 1.endl; return 0; } 等等。 判断值是否相等 #include iostream.h int main() { if(0NULL) cout0 is equal to NULLendl; else cout0 isnt equal to NULLendl; return 0; } 实际上许多编译器对 NULL 的处理方式就是 #define NULL 0 NULL 被用在什么地方 它可以表示空指针可以表示字符串结尾的 /0 符号等等。 下面的类似上面的 #include iostream.h int main() { if(11.0000) cout1 is equal to 1.0000endl; else cout1 isnt equal to 1.0000endl; return 0; } 从现实的角度出发 当然1是等于1.0000 . 而实际上编译器在处理 if(11.0000) 的时候是先把前面的1转化成浮点型的1当然它是等于后面的1.0000了。也就是在程序中出现了不同精度或长度的数据之间的操作的时候要统一转化成一种格式然后再计算这样做也是为了使得计算的结果更精确。 很多人在一些场合看到如下的宏定义 #define NULL 0 那么如下程序该是什么结果呢 #include iostream.h int main() { if(\0NULL) coutEqualendl; else coutIsnt equalendl; return 0; } \0 是个字符串这里使用的字符串 \0 其实是使用它的地址。当然不等于0了。 【上面的字符串的地址能这么肯定不是0吗】 是的。因为笔者的程序运行的Windows操作系统上虚拟地址0其实是不可能因为程序使用而被分配的这个区域是禁止访问的。 如下就的等同的 #include iostream.h int main() { if(\0NULL) coutEqualendl; else coutIsnt equalendl; return 0; } 在这里字符\0是被当做整型0来处理的当然和宏定义的NULL的0是相等的。 我想您对字符串和字符会有更深的理解。 数据类型的最大值和最小值 下面的程序是为了得到整型值的最大和最小值 #include iostream.h #include limits.h int main() { coutINT_MAXendl; coutINT_MINendl; return 0; } INT_MAX和INT_MIN都是宏定义它们在头文件limits.h中 limit就是界限、限制的意思在这里正是这样的意思。 同样还有很多类型有相应的表达如LONG_MAX等等。 这个很有用在有的时候需要得到一种类型的值的极值或者把此当作一个基础值来做比较的分析都很简便了。 如下为此头文件里的定义 【可以用与INT_MAX或INT_MIN的值的对比来测试一个数是否溢出吗】 可能有人会想既然INT_MAX和INT_MIN的值都已经知道了那么测试一个数是否溢出不就可以直接用与它们的大小关系得到吗 如下测试两个int类型的数的和是否超出INT_MAX值的程序 #include iostream #includelimits.h using namespace std; int main() { coutThe biggest number of int type is :INT_MAXendl; int i,j; cinij; if(ijINT_MAX) couti j ij ,Overflow!endl; else couti j ij,Not overflow!endl; return 0; } 而结果如下 得到的结果显然是错误的这也表明不能用这种单纯的方式去判断是否溢出。 Q为什么这种判断不可以呢 A21亿和1亿的和超过了int类型的最大值溢出了但是它的最高位是1即是负数。而用它和int最大值比较的时候它显然比INT_MAX要小也就造成了没有溢出的假象。 【a2】这种表达式 #include iostream using namespace std; int main() { int a3; a 2; //此处是为了看清楚才把两个等号之间加了空格源代码中没有此空格 coutaendl; return 0; } 这里想提的是a 2; 这种语句也被称作表达式语句其实在这里它并没有实质的作用它并没有做赋值改变值的操作也没把这个表达式的值当作条件判断的依据它只是个关系表达式只是加了个分号被看做了语句别的什么也没有。曾经看过一个类似这样的例子一个很大的软件系统就因为这样一个式子导致了巨大的错误是把这类式子看成了具有赋值作用的语句导致的。 于是笔者就在想为什么C语言允许这样的表达式存在确实是没什么实在的作用 当然在编译的时候出现了警告但是警告也丝毫没有改变这类式子存在的可能。 也许是C语言自由的另外一个表现吧。 字符串在一起 将介绍一个关于字符串的程序它是把两个字符串放在一起 #include iostream using namespace std; int main() { coutHello CXendl; return 0; } 这里把两个字符串放到一起编译器会把它们合并成一个字符串然后输出 那么为什么可以有这种机制呢 或许这种方式最简便了。 【自增运算符的弊端】 #include iostream using namespace std; int main() { int x2; int zx/x; coutzendl; return 0; } 这个得到的1是在很难理解 这个程序也真实地表明了自增运算符有的时候确实会造成很大的误解毕竟它这一个运算符的存在要做两件事一件是被使用一件是要自增。那么到低先做哪件事这是出现混乱的根源。C标准从来没有明确表明应该先做哪件事所以在两件事可能造成混乱的地方慎用不行的话就分开为2句话来写。 【字符串的strlen和sizeof】 这个程序是关于字符串的strlen和sizeof值 #include iostream using namespace std; int main() { char *ca; coutstrlen(c)endl; coutsizeof(c)endl; return 0; } strlen这个长度是给程序员看的正如我们想弄明白一个字符串的长度一样 而sizeof带有一点存储的意味更多地倾向与在内存中的存储关系。 【//是写给编译器看的】 C语言中为了表示 / 这个字符必须在它前面加个 / 字符。 原因就是编译器才能看明白。否则那么以 / 开头的转义字符就没有意义了。 编译器忽略空格 编译器是很聪明的正如你写int i1;和 int i 1;一样对它来说这是一样的。 但是这也不是绝对的也有意外。 Q这个程序为什么不能通过编译呢 #include iostream.h int main() { cout 1 endl; return 0; } 编译错误信息为 A为什么你认为它是可以通过编译的呢 Q它不是和这个程序可以看做一样的吗 #include iostream.h int main() { cout1endl; return 0; } A为什么你认为这两个程序可以被看做是一样的呢 Q您不是说过编译器会忽略一些空格、回车符或是TAB符号之类的符号进行有用的代码分析吗这里 cout 1 endl; 不也可以忽略那些回车符和空格之类的把它转化成 cout1endl; 吗 A其实以前说的那些忽略空格之类的理论是有前提的所有的变量、操作符等必须被放在一起的符号是不能用空格、回车符等来隔开的。 Q你是说在这里 cout 1 中 符号是不能隔开的 A是的。你看如下的程序就可以通过编译 #include iostream.h int main() { cout 1 endl; return 0; } 执行如下 问题就在于对比下 cout1endl; 和 cout 1 endl; 我们得先提取标识符包括运算符 从左到右依次有 cout 1 endl 只要不用空格之类符号在它们里面隔开就不会编译错误了。 【运算符也要当作普通标识符来看】 运算符比如这里的也是要把它当作普通变量标识符一样来看待的你把它们分开了编译器当然也就不识别了 Q那么如下的程序也就是可以正确编译的吧 #include iostream.h int main() { cout 1 endl; return 0; } A是的。且执行正常 当然如下的也就编译错误了 #include iostream.h int main() { cout 1 endl; return 0; } 编译的出错信息为 话说Press any key to continue Q函数里什么也不加就会什么也不打印吗 A #include iostream.h int main() { return 0; } Q为什么还会有句话显示呢 A这不是这个程序执行的时候打印的了这是集成开发环境在调试程序的时候打印的语句了 【集成开发环境】 就是开发环境的集成 理论上说编写程序可以不用集成开发环境的用一个记事本写上一段源代码在cmd.exe中用编译的命令VC对C/C代码的编译命令是cl就可以得到我们要的目标代码或可执行程序当然这个需要我们之前安装了这些文件并把它们信息加入环境变量中包括这些命令文件和需要的头文件及链接库文件。 这里是在C盘根目录下执行的cl命令如果已经把cl命令加入了系统环境变量中那么在什么位置都可以执行这个命令 下面举个具体的例子 1、在记事本中编写源代码 保存在C盘根目录下 2、进入cmd.exe转入C盘根目录: 输入cl hello.cpp命令 接着会发现许多编译的时候出现的信息可能有警告不过不要紧 文件夹里已经生产了我们所要的.exe文件了 我们用dir命令 我们发现目标文件、可执行文件确实在这里。 3、执行程序 输入hello.exe: 我们看到了我们要的结果。 现在我们回过头来既然这样就可以那么集成开发环境的作用是什么呢 当然方便是一方面而便于调试应该说是最主要的。 Q也就是说我们如果直接双击这个程序来执行最后不会打印 的吧 A是的。正如我们上面看到的hello.exe,它只是打印了该打印的我们可以回到我们刚刚生成的那个hello.exe文件夹下双击它我们会发现只是一闪而过这表明它已经执行完毕了控制台应用程序就是这样执行完了就会关闭它的窗口。 Q那么如何才能让控制台应用程序执行完了不立即关闭它的窗口呢 A那么可以用getch函数。就用上面的hello.cpp举例在代码中加入getch(); 因为这个函数在conio.h头文件中那么再用#include把这个文件包含上。 #includeiostream #includeconio.h using namespace std; int main() { coutHello World!endl; getch(); return 0; } 执行结果如下我们发现它并没有像以前的程序那样立即出现 Press any key to continue的提示 接着按任意键才出现了Press any key to continue的提示这就是getch()函数起得作用。 我们到这个程序的目录下双击执行 我们发现它并没有像前面那样一闪而过了。 Q那么介绍下getch函数吧。 A 下面介绍两个关于字符操作的重要函数 #includeconio.h int main() { char ch; chgetch(); putch(ch); return 0; } getch还是的作用就是系统等待用户输入一个字符而且输入的字符不会显示在控制台上然后接着执行。 putch还是就是把后面参数中的字符输出到控制台上。 #include iostream #include conio.h using namespace std; int main() { char c; cgetche(); coutcendl; return 0; } 这个程序在输入了一个字符后将先显示您输入的字符接着再去打印它。 getche()函数的作用就是接收标准输入设备一般是键盘输入一个字符显示输入的字符。 它和getch()函数的不同之处在于getch()函数不显示输入的字符。 如下 #include iostream #include conio.h using namespace std; int main() { char c; cgetch(); coutcendl; return 0; } 还有个关于字符操作的函数getchar(): #include iostream #include conio.h using namespace std; int main() { char c; cgetchar(); coutcendl; return 0; } getchar()函数它是接收输入的一个字符但是必须等到接收了Enter键之后才开始它的后续执行。 正如上面输入了一个字符a之后没有接收到Enter键所以还会继续等待 又输入了字符d同样还要等待接着输入了Enter即把缓冲区内第一个字符给变量c,接着执行下面即是打印这个字符也就是a了。 我想大家见过这个函数 getch()还有个是getchar()如果您更深入还有个getche()当然它们都有个目的就是等待操作者去输入一个字符然后才会继续;这在一个场合很有用的比方说您的程序要输出很多然而你希望是一段一段地看免得一下都输出了上面的都不好找了甚至就是被CMD给忽略了那么用这个暂停下给你足够的时间去看当然它们3个之间是有区别的以后介绍。 【kbhit函数】 下面介绍一个不常用的一个函数 kbhit是keyboard hit的意思。 int kbhit(void); 位于头文件conio.h下 作用是检测是否有键按下如果有则返回非0值即真否则返回0(即假)。 如下程序 #include iostream #includeconio.h using namespace std; int main() { int i; for(i0;!kbhit();i) coutiendl; return 0; } 执行的时候会看到 您不按键它就继续执行下去除非你按键了那么它就立刻退出了循环当然是因为!kbhit()的取值为假了 那么有人会问了那它和getch()函数什么区别呢 kbhit() 在执行时,检测是否有按键按下,有按下返回键值 没有按下返回0;是非阻塞函数 getch() 在执行时,检测按下什么键,如果不按键该函数不返回;是阻塞函数。 这个函数在调试某些程序时很有用。 { } 到底是什么 当然这是和我们想的一致的那么您可能有这样的怀疑了{ } 这种符号到底是做什么的 虽然很多人都知道这是一个函数的开始和结束的标志或许还可能是一个if语句、for语句等等能奏效的范围 那么如下的您认为可以么 { #include iostream.h int main() { return 0; } } 真的不对 错误原因是missing function header 那下面的呢 #include iostream.h int main() { return 0; } { } 哦当然还是不对的了原因一样missing function header 还有这个呢 #include iostream.h { int main() { return 0; } } { } 可以是一个函数的执行体部分的开始和结束标记也可以是if条件语句的执行体范围的标记可以是switch语句后面包含各个case的包含符甚至可以当作是在任意一段执行代码中一个内嵌的域正如 #include iostream using namespace std; int main() { int i1; { int i2; coutiendl; } coutiendl; return 0; } 你可以分清楚两个i的不同作用范围吗 这个将在后面的变量的作用域中详细讲解。 深入scanf函数 下面是关于输入和输出的程序 #include iostream.h #include stdio.h int main() { int a; coutInput a number:endl; scanf(%d,a); coutaendl; return 0; } 这个大家很熟悉了。 而下面的呢 #include iostream.h #include stdio.h int main() { int a; coutInput a number:endl; scanf(%d,a); coutaendl; return 0; } 这个与上面的不同之处就在于scanf还是后面的变量a前面没有加取地址符,结果呢 得到了一个很诡异的值。 为什么会这样呢 这还得从scanf说起。它后面的双引号后面必须用变量地址把前面双引号内地变量由用户从标准输入设备一般是键盘输入到那个地址里。 第一个程序做到了 第二个呢是把自身当作地址了当然这是不对的了。 #include stdio.h #include iostream.h int main() { int a; coutInput a number:endl; scanf(%d,a); printf(%d\n,a); } 本来是个很简单的程序但是要求输入十进制整型我们却输入了一个字母a,结果果然和我们想的不一样。 为什么会这样 在输入了一个字母a而不是整型需要的数字0~9的话那么程序自动认为输入结束。那么这里的变量a程序是使用了堆栈处的值给赋值的。当然堆栈处的值目前是脏数据。 【用指针实现scanf中输入变量地址】 既然scanf函数是语法是这样的我们不妨用指针来表达其中的输入变量的地址。 如下 #include iostream.h #include stdio.h int main() { int a; int *paa; coutInput a number:endl; scanf(%d,pa); coutaendl; return 0; } 我们发现编译没错运行也很正常 Q那么为什么scanf函数后面要用变量地址呢理论上说用变量名不也可以吗 A你说的有道理。如果把这个位置用变量名来表示改下编译器其实也可以表达输入的值放到这个变量里。但是对于scanf这个基本输入函数要对所有类型都适用才可以如果是数组呢 对于声明的数组我们能用的只是它的数组名可是它就是地址。那么如何表达输入一个字符数组也就是字符串的一种形式呢 char c[6]; scanf(%s,c); 这里的c是什么它是个地址。 我想上面这个程序在这个位置用地址就是为了和形如字符数组的输入相统一。 关于注释 注释可以防止因为时间的原因导致忘记了代码的意思了而且对于别人对代码的维护也有极其重要的参考价值。 C语言有2种注释方法一种是/* */方式就是把要注释的代码放到/*和*/之间。 但是这种无法嵌套。 第二种是 C还提供了一种很简洁的单行注释方式// . 注释是程序代码中重要的组成部分尤其在大型软件制作中注释是极其重要的。 介绍的将是C中更让人惊叹的代码 #include iostream using namespace std; int main() { int a /*This is the value of a*/ 2; cout aendl; return 0; } 注释可以放到代码中一般来说都是代码后面后是自己独立成行 像上面这样代码和注释居然可以如此亲密没有编译和链接的错误还真是少见 不过由此加深大家对C语言自由的理解深度 #include iostream using namespace std; static int div(int *divisor) { int result5; resultresult/*divisor; /*Do divide */; *divisor1; return result; } int main() { int num5; coutdiv(num)endl; return 0; } 这里又一次展示了注释在代码中的奇特表现 编译器支持中文吗 Q程序中可以输出中文信息吧 A是的可以。一般新点的编译器都会支持的。 TC3.0编译器不支持中文如下代码 #include iostream using namespace std; int main() { cout您好endl; return 0; } 执行结果是 逗号表达式 下面是个类似逗号表达式的程序 #include iostream using namespace std; int main() { long one_million; one_million1,0,0; coutone_millionendl; return 0; } 为什么会得到这个结果呢 如果说1,0,0这个位置可以用逗号表达式来解释那么值也是最后一个的0啊为什么最后打印的是1呢 微风不燥阳光正好你就像风一样经过这里愿你停留的片刻温暖舒心。 我是程序员小迷致力于C、C、Java、Kotlin、Android、iOS、Shell、JavaScript、TypeScript、Python等编程技术的技巧经验分享若作品对您有帮助请关注、分享、点赞、收藏、在看、喜欢您的支持是我们为您提供帮助的最大动力。 欢迎关注。助您在编程路上越走越好