·操作符
-算术操作符
/ 可以对浮点数进行计算
% 只能对整型计算
-移位操作符
右移操作符 :
1.算术右移
右边丢弃,左边补原符号位(正为0,负为1)
n/2 等价于 n>>1
2.逻辑右移
右边丢弃,左边补0
-整数的二进制表示
原码,反码,补码
-在内存中储存的是补码
-1:
原码10000000000000000000000000000001
反码11111111111111111111111111111110
补码11111111111111111111111111111111(反码加1)
-正整数的原码、反码、补码相同
左移操作符:
左边丢弃,右边补0
·对于移位操作符,不要移动负数位,这个是标准未定义的
·位操作符 -操作对象必须为正整数
& 按位与 只要有一个为0即为0,同时为1才为1
| 按位或 只要有一个1即为1
^按位异或 相同为0,相异为1
·赋值操作符
-复合操作符
·双目操作符 -有两个操作数
·单目操作符 -仅有一个操作数
!逻辑反操作 :真变成假,假变成真
-取负值
+取正值
& 取地址
*解引用操作符
sizeof( )计算变量/数组/内存所占内存空间的大小,单位是字节
-sizeof中的操作不会对参数产生实际影响
~ 按位取反
++,前置++,先++后使用 ;后置++,先使用后++
--,前置--,后置--
-printf函数中的操作会对参数产生实际影响
(类型)强制类型转换
-数组传参时穿的是首元素的地址
·双目操作符
-逻辑操作符
逻辑与 &&
-若&&左边出现假,整体直接为假,右边不再计算
逻辑或 | |
-若 | |左边出现真,整体直接为真,右边不再计算
·条件操作符(三目操作符)
exp1?exp2:exp3
·逗号表达式
-从左到右依次计算,整个表达式的结果为最后一个表达式的结果
//逗号表达式
#include<stdio.h>
int main(void)
{
int a = 1;
int b = 2;
int d = 1;
//
int c = 0;
if (a=b+2,b=a+3,d>0)
{
c = a + b;
}
printf("c=%d\n", c);
return 0;
}
·下标引用操作符
-操作数:一个数组名+一个索引值
·函数调用操作符 ( )
操作数:函数名和各个参数
·结构体类型
·结构体的传参
-传值调用
-传址调用
-元素调用
·隐式类型提升
--整型提升(对于小于整型的类型)
-若计算式一个表达式不能达到整型的大小,该表达式会发生整型提升
-提升方式:按符号位进行提升,若无符号直接补0
-提升至32bit
-意义:便于cpu运算
//整型提升
#include<stdio.h>
int main(void)
{
char a = 3;
//00000000000000000000000000000011
//00000011
char b = 127;
//00000000000000000000000001111111
//01111111
char c = a + b;
//对a,b进行整型提升
//00000000000000000000000000000011(a)
//00000000000000000000000001111111(b)
//相加
//00000000000000000000000010000010
//10000010(c)
//对c进行整型提升
//11111111111111111111111110000010(补码)
//11111111111111111111111110000001
//10000000000000000000000001111110
//-126 (int)c
printf("c=%d\n", c);
}
--算数转换
-小类型转换为大类型
·操作符的相关属性
-优先级
-结合性
-是否控制运算顺序
·在求值时要确保表达式的求值顺序是唯一的
·指针
-指针变量用来存放地址
-指针就是地址
-每个地址 标识 一个字节
-32位机器地址需要4个字节来存储
·指针类型的意义
-指针类型决定了指针进行解引用操作时能够访问空间的大小
int* p *p能够访问4个字节
char* p *p能够访问1个字节
-指针类型决定了指针向前或向后走一步的距离
int* p:p+1--->4
char* p:p+1--->1
·野指针
-指针指向的位置不可知(随机的,不正确的,没有明确限制的)
//野指针_1
#include<stdio.h>
int main(void)
{
int* p;//局部变量未初始化默认是随机值
*p = 20;
return 0;
}
//野指针_2
#include<stdio.h>
int main(void)
{
int arr[10] = { 0 };
int* p = arr;
int i = 0;
for ( i = 0; i < 12; i++)//超出arr的范围的指针是野指针
{
//*(p + i) = 1;
//*p = i;
//p++;
*p++ = i;//与前面两行代码效果相同
}
}
//野指针_3
#include<stdio.h>
int* test()
{
int a = 10;//申请一块内存存放局部变量a
return &a;//存放a的内存被释放
//int arr[] = { 0 };
//return arr;//数组同理
}
int main(void)
{
int* p = test();//离开test函数时存放a的内存被释放
*p = 20;//指向了一块被释放的内存
}
产生原因:
1.指针未初始化
2.指针越界访问
3.指针指向的内存释放
-局部变量不初始化默认是随机值
-规避野指针
1.初始化指针
2.小心指针越界
3.设置已释放的指针为NULL
4.使用之前检查有效性(NULL指针不能使用)
·模拟实现strlen函数计算字符串长度的三种方法
#define _CRT_SECURE_NO_WARNINGS 1
//模拟strlen函数求字符串长度
//1.计数器
//#include<stdio.h>
//
//int my_strlen(char* str)
//{
// int count = 0;
// while (*str != '\0')
// {
// count++;
// str++;
// }
// return count;
//}
//
//int main(void)
//{
// char arr[] = "hello";
// int len = my_strlen(arr);
// printf("len=%d\n", len);
// return 0;
//}
//2.函数递归
//#include<stdio.h>
//
//int my_strlen(char* str)
//{
// if (*str != '\0')
// {
// return 1 + my_strlen(str + 1);
// }
// else
// {
// return 0;
// }
//}
//
//int main(void)
//{
// char arr[] = "hello";
// int len = my_strlen(arr);
// printf("len=%d\n", len);
// return 0;
//}
//3.指针运算
#include<stdio.h>
int my_strlen(char* str)
{
char* start = str;
char* end = str;
while (*end != '\0')
{
end++;
}
return end - start;
}
int main(void)
{
char arr[] = "hello";
int len = my_strlen(arr);
printf("len=%d\n", len);
return 0;
}