南山附近公司做网站建设多少钱,wordpress 网站关键词设置,个人免费自助建站,网站建设趣味解读1 整数的存储
只有整数才有原码#xff0c;反码#xff0c;补码#xff0c;原码取反加一#xff08;除了符号位#xff09;得到补码。补码的补码会变成原码。 在任何位运算里#xff0c;都是操作的补码#xff0c;因为整数在内存里都是以补码存储的
2 移位运算符
移位…1 整数的存储
只有整数才有原码反码补码原码取反加一除了符号位得到补码。补码的补码会变成原码。 在任何位运算里都是操作的补码因为整数在内存里都是以补码存储的
2 移位运算符
移位运算符只能用与整数且移动二进制位的补码不改变这个数本身的值左移,左边丢弃右边补零右移分为逻辑和算数一般右移与编辑器有关。1. 逻辑右移左边⽤0填充右边丢弃 2. 算术右移左边⽤原该值的符号位填充右边丢弃在进行完位运算后得到的仍然是补码。
3 位运算符 位操作符 | ^ ~ 有0则为0同时为1则为1可以用真假来记 | 有1则为1同时为0才是0 ^ 相同为0相异为1 ~ 按位取反包括符号位 异或的一些技巧 异或支持交换率即与运算顺序无关 3^3^53^5^3 a^a0 0^aa 基于以上特点可以用于交换两个变量但不使用第三个变量 int a 5;
int b 10;
a a ^ b;
b a ^ b;
a a ^ b;4 求一个正数在内存里存储的二进制中的1的个数 方法一只能用于正数 int count 0;int n 15;while (n0) {if (n % 2 1) {count;}n / 2;}printf(%d, count);方法二一个数在1之后如果1则说明该位是1否则则为0int count 0;int n -1;for (int i 0; i 32;i) {if ((n i) 1 1) {count;}}printf(%d, count);方法三n n (n - 1)这样写执行一次该代码会去掉二进制里最右边的一个1相当于将最右边的一个1拆成0……1int count 0;int n -1;while (n ! 0) {n n (n - 1);count;}printf(%d, count);
5 逗号表达式
………………从左向右依次进行计算整个表达式的结果是最后一个表达式的结果常和while函数一起使用
6 结构体
创建结构体
struct stu {int age;char name[10];
}s2,s3;初始化使用{}struct stu s1 {10,zhangsan};。也可以不按顺序初始化struct stu s4 { .name lisi,.age 20 };可以用 . 访问成员printf(%d, s1.age);
7 整型提升
C语言中整型算术运算总是至少以(int)整型类型的精度来进行的。为了获得这个精度表达式中的字符和短整型操作数在使用之前被转换为普通整型这种转换称为整型提升。在 C 语言中使用char类型变量存储数字时确实只能存储该数字二进制表示的前 8 位。有符号整数提升是按照变量的数据类型的符号位来提升的无符号整数提升高位补0在计算时提升计算完在截断char只能在[-128,127]在以%d 打印一个char类型的变量的时候会先对该变量进行整型提升得到补码在转化为原码进行打印一般默认是有符号char
8 算数转换
如果某个操作符的各个操作数属于不同的类型那么除非其中⼀个操作数的转换为另⼀个操作数的类型否则操作就无法进行。下面的层次体系称为寻常算术转换。在比较有符号整型和无符号整型时有符号整数会被隐式转换为无符号整数。转换的方式是保留二进制位不变但是将其解释为无符号数。例如在 32 位系统中有符号整数 -1 的二进制表示是 0xFFFFFFFF补码形式。当把它转换为无符号整数时同样的二进制位 0xFFFFFFFF 会被解释为无符号数 4294967295。
9 指针
如果对一个int类型取地址取到的是最小那个地址一个int4个字节每个字节都有自己对应的地址a则代表最小那一个地址任何数字存入指针变量里都会被当作指针处理一个指针变量在32位机器上是32个0/1组成的序列需要4个字节来存储在64位机器上是64个0/1组成的序列需要8个字节来存储不同的指针类型在解引用时访问的字节数与指针类型有关不同的指针类型会影响1的步长
10 void*指针
泛型指针可以理解为⽆具体类型的指针或者叫泛型指针这种类型的指针可以⽤来接受任意类型地址。但不能对该指针进行解引用和±操作。经常用于接受不同类型的函数参数在使用时可以先强制类型转化后在使用。
11 指针运算 指针±整数 *(pi)或者 scanf(“%d”, p i)这里的pi本身就表示一个地址 不只可以加上一个整数还可以减去一个整数,在这个程序里int* p arr[9];此时p里面存放的是最后一个元素的地址也可以从这里向前访问。 int arr[10] { 1,2,3,4,5,6,7,8,9,10 };
int* p arr[9];
for (i 0; i sz; i)
{printf(%d , *(p - i));
} 指针-指针 只有指向同一块区域的指针才可以相减比如指向同一个数组的内存 相减的结果的绝对值是两个指针之间的元素个数 int arr[10] { 0 };
int n arr[0] - arr[9];
printf(%d , n); 指针的关系运算(可以用这种关系运算来判断一个数组是否已经结束) int arr[10] { 1,2,3,4,5,6,7,8,9,10 };
int sz sizeof(arr) / sizeof(arr[0]);
int* p arr;
while (p arr[sz]) {printf(%d , *p);p;
}12 strlen函数的实现
方案一计数器
size_t my_strlen(char* str){size_t num 0;while (*str ! \0) {num;str;}return num;
}int main()
{char arr[] abcdef;size_t len my_strlen(arr);printf(%zd, len);return 0;
}
方案二运用指针相减
size_t my_strlen2(char* str) {char* start str;while (*str ! \0)str;size_t num (size_t)(str - start);return num;
}13 const修饰指针 对于const int n 10;会让n变成常变量无法被修改但仍然是一个变量。 const修饰的变量不能直接被修改但可以通过指针侧面进行修改
const int n 10;
int* pn ;
*p 1;
printf(%d , n);如果不想让这个值被指针修改只需要在int*前也加上const
const int n 10;
const int* pn ;
*p 1;
printf(%d , n);const int * p const放在左边修饰的是整个*p也就是可以不能修改p指向的内容但指针变量本身可以修改即可以从指向a变为指向b int * const pconst放在*的右边修饰的是p本身也就是不可以修改p本身即p的指向但可以通过p修改p指向的内容即 *p
14 野指针 这里面就造成p变成了一个野指针因为在test结束的时候n空间就释放了
int* test() {int n 100;return n;
}int main() {int* p test();printf(%d , *p);return 0;
}15 assert断言
assert包含在头文件assert.h里如果在开头加上#define NDEBUG
会直接让程序里所有的assert断言都失效
int* p a; assert(p ! NULL)如果p为NULL会直接终止程序该断言只有在debug模式里才有用在release模式则会忽略该语句。
16 指针与数组
数组名是数组首元素的地址但存在两个特殊情况 sizeof(数组名) 在这种情况下数组名表示整个数组计算出的结果是整个数组的大小单位是字节数组名 这里的数组名也是表示整个数组取出的是整个数组的地址类型不是int*
17 一维数组传参的本质
在实际以数组传参的时候传递的就是一个地址也就是如果数组经过传参就彻底变成首元素的地址没有特殊情况了不可以用sizeof(arr) / sizeof(arr[0])来计算数组长度了。所以如果想知道数组的长度必须在传参的时候传过去
18 冒泡排序 两两相邻的元素进行比较 一趟解决一个数字所以需要n-1次 void bubble_sort(int* pa,int len) {for (int i 0; i len-1; i) {//控制一共运行几次如果有n个元素只需要运行n-1次即可因为最后一个元素会自行有序int flag 0;for (int j 0; j len-1-i; j) {//控制在一次循环里比较几对数据if (pa[j] pa[j 1]) {int tem pa[j];pa[j] pa[j 1];pa[j 1] tem;flag 1;}}if (flag 0) {break;}}
}//flag是为了优化代码如果有一次外层循环一次都没有交换(flag0)则说明已经有序可以直接结束break19 二级指针 int** p就是二级指针int *说明p指向一个int *类型的数据而第二颗 *则说明p是一个指针变量 int a 10;
int* pa a;
int** ppa pa;20 指针数组 存放指针的数组 模拟二维数组与二维数组有不同因为二维数组每一行之间是连续空间 int main() {int a[3] { 1,2,3 };int b[3] { 4,5,6 };int c[3] { 7,8,9 };int d[3] { 10,11,12 };int* arr[4] { a,b,c,d };//数组名是首元素地址for (int i 0; i 4; i) {for (int j 0; j 3; j) {printf(%d , arr[i][j]);}printf(\n);}return 0;
}21 字符指针 在打印字符串的时候只需要传入该字符数组首元素的地址const char* p hdjslds;printf(%s,p); 字符指针可以被赋为字符数组也可以直接用常量字符串赋值,两者的区别是常量字符串不可以被修改 char* p hdjslds;char arr[10] hdjslds;
char* p arr; 对于同一个常量字符串即使使用多个指针变量指向它都指向的是同一块内存空间即同一个常量字符串因为它无法被修改所以没必要创建多个 const char* str1 hello;
const char* str2 hello;
if (str1 str2) {printf(same);
}22 数组指针变量
指向整个数组的指针int(*p)[5] 其中*p说明p是一个指针变量[5]说明p指向的是一整个数组5代表元素个数int 代表指向这个数组里边存放的元素的数据类型