c语言其三
一.操作符双目操作符1.除号 / 两端如果都是整数则它执行的是整数除法结果必须用%d来占位如果想出现小数必须两边至少一个浮点数2.%是取模操作符只能用在整数不可以用在浮点数上特别的负数求模正常计算然后符号跟第一个运算符一样。3.a与a看加号在哪里放前面就是先加一后使用原本的a的值发生不变放后面就是先使用再加一原本的a改变在哪里决定加1的顺序int a10int ba这时候就是先使用让b10再对a进行加1这里a11b10int ba这时候就是先加一让a11再使用则b11关系操作符1.关系表达式的结果真为1假为0规定好的c语言中0为假非零为真2.判断两个数据是否相等的时候如果有一个是常量的时候常量建议写在左边3.关系操作符不宜连用会导致错误比如9022100,明显就是错误的但是90不小于22返回一个00小于100所以又真起来了。4.强制类型转换:比如说int aint3.14将这个double类型的3.14转换成int将默认的3.14转为浮点型只需在末尾加上一个f三目操作符条件操作符形式表达式1 表达式2 : 表达式3当表达式1为真2算3不算表达式1为假3算2不算2和3谁算了就是整个表达式的结果。短路现象在逻辑运算符中如果左边的表达式能确定整个表达式的值则不会再对右边进行求值计算例如上面这个代码出来的结果应该是2 3 3 5这是因为a这个先用再加然后ab左边为1在这个并且中右边b也执行a就变成2b就变成3d同理变成5。但是如果将a改为0所以ab左边为0确定整个表达式了则右边b不再执行所以a变成1b还是2d同理也没变还是4。注意思考一下将换成| |的时候abcd又是怎样的变化a0 1334 a1 2 2 3 4逻辑操作符1. !逻辑取反改变单个表达式的真假2.逻辑与相当于并且全真才真一假即假适用于需要同时成立的时候。3. | |逻辑或相当于或者一真即真适用于不同时满足但又必须满足一个位操作符依旧针对整数依旧是补码按位与 对应二进制进行计算有0则为0同时为1才是1按位或| 只要有1则为1同时为0才是0按位异或^ 对应二进制位相同为0相异为1按位取反~ 原来是0变成1原来是1变成0异或支持交换律:公式如下 a. x^x0 b. 0^xx码数整数的二进制表示方法有三种原码反码补码其中有符号整数的表示包含符号位和数值位最高的一位是符号位用0表示正1表示负计算机中存储的就是补码但打印出来的就是原码。cpu中只有加法运算正整数以及无符号整数的原码反码补码是一样的负数的三个均不相同需要一定计算。原码就是直接将数值按正负数的形式打出来的反码就是除了原码的符号位不变其余的取反反码加一就是补码。补码取反加一可以直接得到原码移位操作符 和 只针对整数但不可以移动负数位左移的规则是左边抛弃右边补零右移看是什么移动了一般是算术右移也就是左边用原该值的符号位填充右边丢弃。逻辑右移仅了解左边用零填充右边丢弃。 本质上是移动存储的补码下标引用操作符[ ] ,arr[ 5 ]中arr和5都是[ ]的操作数函数引用操作符同理但是至少一个操作数。整型提升1.定义c语言中整型运算总是以默认整型类型int来进行计算在对字符以及短整型的运算会先将其转换为普通整型最简单的理解是吃西瓜计算机cpu一个个挑籽不乐意必须一整块一起吃整型提升再吐籽(计算后截断放回char里面)2.怎么做无符号整数高位统一补0进去直到凑够32位取决于计算机。有符号整数根据符号位填充高位正数补0负数补1.6.char类型的取值范围是-128到127上例子(默认char是 signed char)char a20char 120char cab 在vs2022中c-116原因140127所以溢出了所以进行最低层的计算char c是占一个字节8个比特位可以存8个二进制0/1补码算出来之后是1000 1100在无符号整数里这是140但是这里识别成有符号则此数字为负数负数打印出来要取反加一则为 0111 0100算出116再加上符号变成-116。不管怎么截都是截取低位的地址优先级:一个表达式内含多个运算符这时候就有先后之分了结合性当优先级一样时就看结合性决定执行顺序左结合是从左到右执行右结合就是从右到左执行。二.指针基础1.一个比特位可以储存一个二进制的位1或0,是最小单位1Byte 8bit 每个内存单元Byte都有其对应编号由硬件决定32位机器就有2^32种含义每一含义都对应一个地址这个编号就是这个内存单元的地址在c语言中也叫做指针。2.如何找到变量的地址就涉及到取地址操作符a是在内存中取出a变量所占字节中地址较小的字节的地址然后根据类型就可以精准找到变量a的所有地址。还有一个操作符就是解引用操作符间接访问操作符*例如int a10int*pa; *p0;这三行代码当第二行写出来的时候*p其实已经约等于a变量了当第三行出来的时候就把a变量赋值为0了。3.指针也可以有变量小空间指针变量的意思就是专门用来存放指针地址的变量形式为 int * p aint说明a变量的类型是整型*说明p是指针变量里面存着a变量的地址存在指针变量里面的值都会被认为是地址。如果p是指针变量*p表示p所指向的内存位置上的值而不是p存储的地址值。p本身存储的才是地址值4。指针变量的大小32位机器上地址是由32根地址线传递的一个地址就是32个0/1的二进制需要32个bit存储4个字节所以在32位机器上指针变量的大小就是4个字节64位机器就是8字节他等于地址存储的空间大小也就是说指针变量的大小与类型无关在相同平台下大小都是相同的。5.不过指针大小虽然是一样的但是指针类型决定了对指针解引用的时候有多大权限例如char只能访问一个字节而int可以访问4个字节指针类型还决定了指针向前或向后走一步有多大距离。6.与函数一样的指针也存在void *指针他可以接收任意类型的地址如果将一个int类型的地址赋值给char类型的指针变量会出现类型不兼容这时候赋给void就不会有这个烦恼是泛型指针不过他不能直接进行指针的加减整数和解引用运算。5.野指针当指针指向的空间不属于当前程序的时候这时候指fucheng针指向的位置是不可知的此时这个指针就是野指针。野指针成因a.忘记初始化指针 b.指针越界访问 c.指针指向空间释放指向生命周期已结束的NULL的介绍这是c语言中规定的标识符常量值为00也是一个地址但是该地址无法使用强行读取该地址会报错int *paNULL意思为p变量暂时没有指向有用空间孤立这个变量现在不要去使用它用完一个指针的时候不想用了可以把指针赋成空指针想用的时候再次调用即可。6.二级指针用来存放一级指针变量的地址的指针int a 10; int *pa a; 这两行代码pa是指针变量同时也是一级指针变量就有自己的地址int **ppapa此时这个ppa就是二级指针变量。与上面3.类似第一个*说明ppa指向的对象是int *类型的第二个*说明ppa是指针。9.指针数组在多次都取地址并存到指针变量里代码要写很多重复的部分很麻烦于是有了指针数组如下这时候统一一个指针数组将123所有地址存了起来10.字符指针变量这里前两行是定义一个可修改的数组并初始化为abcdef,pc是字符指针变量指向的是数组首元素地址而注释掉的这一行是将pc这个指针变量指向常量字符串中首元素a的地址但是该字符串不可修改11.传值调用与传址调用根本在于*操作符传值只是传递值的副本在函数内部修改并不影响实参传址调用传递的是这个值存储的地址在函数内改变影响这个实参。二.指针计算1.指针减指针:得到两个指针之间的元素个数特别的指针中不可以进行相加相乘和相除相减的前提是两个指针指向同一块空间否则不能进行相减。2.这里涉及到指针的大小比较简单说就是计算地址的高低变换重点是我这里注释掉的这两行代码,数组名在大部分场景下指向数组首元素的指针需要注意两点1.sizeof(数组名) —— 此时数组名代表整个数组计算的是整个数组的字节大小2.数组名 —— 此时数组名代表整个数组arr 的类型是 “指向整个数组的指针”例如int (*) [10] )而非指向首元素的指针,如果移动起来首元素只移动一个元素大小而后者是移动整个数组的大小。所以在这里int*parr,p指向的是单个指针与整个数组的指针类型不匹配会报错还有长度计算也会算不出来。3.由上面可以推出连等公式 arr [ i ] *(arri) *iarri [ arr ] 等价的但是不常用后面的两个3.const修饰指针const是常属性的意思也就是不能进行修改此图说明a变量已经被锁定限制了a的修改但a本质上还是变量。4.修饰指针变量的时候const可以放前面也可以放后面具体如下const int* p a; 或 int const * p a;const放前面与放后面的区别放前面限制的是pa指向的对象也就是限制*pa的更改。但是pa不受限制此时指针变量可以进行指向原来的地址的改变放后面限制的是pa也就是也就是pa不可以更改了但是*pa不受限制此时pa指向的内容可以通过pa进行修改简单说就是放前面指针p可以更换存储地址但是不能通过*pa来改变原本a或b的值int a 10, b 20;const int *p a; // p一开始指向ap b; // 现在p指向b了放后面指针只能指向一个地址但是可以更改原本存在这的值。三.冒泡排序1.定义:两两进行比较数字按照一定关系进行对换2。原理要通过外循环控制排序的轮数a总数-1内循环随着趟数进行一个个减少总数-1-轮数可以加计数器判断是否有参与内循环中的比较来提升效率四.字符函数和字符串函数1.字符分类函数:头文件ctype.h2.字符转换函数:tolower大写转小写toupper小写转大写3.strlen函数:统计字符串\0之前的字符个数参数char*str ,是一个指针指向要统计长度的字符串返回值返回字符串长度由于长度不会是负数所以是size-t类型无符号整数必须要有\0结尾必须包含头文件string.h模拟实现法一计数器法二。指针减指针法三递归4.strcpy函数strcpy目的资源字符串拷贝拷贝到源头字符串中的\0为止会把目标空间覆盖掉返回值是目标空间的起始地址数组名是地址是一个常量不能被修改无法直接赋值但是目标空间必须要可以修改目标空间必须足够大能够放得下源字符串必须以\0结尾且这个\0会被拷贝到目标空间5.strcat函数strcat(目的资源)在末尾进行字符串拼接返回值还是目标空间的起始地址6.strcmpstrcmpconst char*str1const char*str2字符串比较str指的是指针传递的是第一个字符的地址如果第一个字符串大于第二个字符串则返回大于0的数字如果相等就返回0从第一个字符开始比较ASCII码值相等就比较下一个字符直到结束或者遇到不相等的字符7.strncpystrncpy(char*目的地const char *source size_t num)字符串拷贝,把source里的字符串拷贝到目的地指向的空间中最多拷贝num个字符不够num个自己会补\0直到补够num个而且他会默认\0就是终止返回值是目标空间的起始地址是char*类型的在结尾加上8.strncatstrncatchar*目的地const char *source size_t num把source里指向的字符串内容追加到目的地里面最多追加num个字符返回值是目标空间的起始地址是char*类型的在结尾加上其中\0也会加上无论你加几个字符但是不够的话不会多补\09.strncmpstrncmpconst char *str1const char * str2 size_t numstr指向要比较的字符串num是最多比较num个字符如果第一个字符串大于第二个字符串则返回大于0的数字如果相等就返回0返回值类型是int10.strstrstrstrconst char *str1const char * str21是被查找字符串2是要查找字符串在一个字符串中找另一个字符串子字符串第一次出现的位置找到了返回地址找不到则返回空指针NULL11.strtokchar * strtokchar*str const char *delim分割字符串根据delim参数里指定的分隔符将字符串str拆分成多个子字符串修改原字符串strtok会直接在原始字符串中插入 \0 终止符替换分隔符位置因此原字符串会被修改str首次调用时传入待分割字符串后续调用传入NULL表示继续分割同一个字符串delim包含所有可能的分割字符串多个分割符会被视为一个分隔符不会返回空指针返回值,成功时返回指向当前子字符串的指针没有更多字符串时返回NULL常与for循环一起12.strerrorchar* strerrorint errnum可以通过参数部分的errnum表示错误码得到对应的错误信息并返回这个错误信息字符串首字符的地址c语言的库函数在使用的时候如果出错会将一个错误码记录到errno的变量里只针对标准库里的函数出错后设置的错误码需要包含string.hperror........相当于直接打印参数部分的字符串后再打一个冒号和空格再打印错误信息void perrorconst char*str如perror text test:错误信息五.内存函数1.memcpyvoid * memcpyvoid*目的地const void *source size_t nummemcpy是完成内存块拷贝的不关注内存中存放的数据是什么如果source和目的地有任何重叠复制的结果都是未定义的目的地指针指向目标空间拷贝的数据放在这里num要拷贝的数据占据的字节数返回值拷贝完成后返回目标空间的起始地址2.memmovevoid * memmovevoid*目的地const void *source size_t num与memcpy是几乎一样的但是他可以解决重叠问题3.memsetvoid*memset void*ptrint valuesize_t num把内存块中指定长度的空间设置为特定的内容ptr指针指向要设置的内存空间也就是存放了要设置的内存空间的起始地址value要设置的值会把value的值转换成unsigned char的数据进行设置也就是按字节来修改而不是一个元素num要设置的内存长度单位是字节头文件string.h4.memcmpint memcmpconst void*ptr1const void*ptr2size_t num内存块内容的比较单位是字节返回值有正有负六.数据在内存中的存储1.整数在内存中的存储数据存储其实是存放二进制的补码正整数的原反补码都相同负整数正常翻译出原码然后原码符号位不变按位取反得反码反码加一得补码2.大小端字节序和字节序的判断超过一个字节的数据在内存中存储的时候就有存储顺序问题倒着存叫小端字节序存储正着存叫大端字节序存储大端字节序存储将一个数据的高位字节的数据存储在低地址处低位字节的数据放在高地址处小端字节序存储:与之相反