c语言_Day21_07_22
1、表达式求值表达式求值需要注意两部分内容:优先级顺序和类型转换
1、类型转换
[*]隐式类型转换
[*]整形提升:表达式中的字符和短整形操作数在使用之前被转换为普通整形
int main()
{
char a = 3;
char b = 127;
char c = a + b;
printf("%d", c);
return 0;
}
[*]当用a(b)存放3(127)时,a(b)的空间大小为1byte,而3(127)的数据大小为4byte,故数据需要发生截断
[*]字符相加需进行整形提升(按数据类型的符号位进行提升),再计算
[*]将计算结果存放至c中,c的空间大小位1byte,而结果为整形,故数据需要截断
[*]打印整形,故c发生整形提升,得到补码,再转至原码打印
整型提升补充数据规则:
[*]正数补零
[*]负数补一
[*]无符号数补零
验证整形提升:int main()
{
char a = 0xb6;
short b = 0xb600;
int c = 0xb6000000;
if (a == 0xb6)
{
printf("a");
}
if (b == 0xb600)
{
printf("b");
}
if (c == 0xb6000000)
{
printf("c");
}
return 0;
}只有在算术运算符、位运算符和关系运算符的计算中发生整形提升
[*]算术转换:对于存储空间大于int的数据类型,进行计算时应转换为存储空间较大的数据类型再执行计算
long double
double
float
unsigned long int
long int
unsigned int
int2、优先级
[*]操作符优先级(高 -> 低)
[*]结合性
() 聚组 NR
() 函数调用 LR
[] 下标引用 LR
. 访问结构成员 LR
-> 访问结构指针成员 LR
++ 后自增 LR
– 后自减 LR
! 逻辑取反 RL
按位取反 RL
+ 单目,表示正值 RL
- 单目,表示负值 RL
++ 前自增 RL
– 前自减 RL
* 解引用 RL
& 取地址 RL
sizeof RL
(类型转换) RL
* 乘法 LR
/ 除法 LR
% 取余 LR
+ 加法 LR
- 减法 LR
<< 左移 LR
>> 右移 LR
> 大于 LR
>= 大于等于 LR
< 小于 LR
<= 小于等于 LR
== 等于 LR
!= 不等 LR
& 按位与 LR
^ 异或 LR
| 按位或 LR
&& 逻辑与 LR
|| 逻辑或 LR
?: 三目表达式 NR
= 赋值(赋值操作符)RL
, 逗号表达式 LR
[*]控制求值顺序(是否存在短路逻辑)
问题表达式:在已知优先级、结合性等性质下仍无法给出唯一解的表达式(以下均为问题代码)
// 表达式1
a*b + cd - ef
// 表达式2
c + --c
// 表达式3
int main()
{
int i = 10;
i = i-- - --i * ( i = -3 )i++ + ++i;
printf("%d\n", i);
return 0;
}
// 表达式4
int foo()
{
static int count = 1;
return ++count;
}
int main()
{
int res = foo() - foo()foo();
printf("%d\n", res);
return 0;
}
// 表达式5
int main()
{
int i = 1;
int res = (++i) + (++i) + (++i);
printf("%d\n", res);
printf("%d\n", i);
return 0;
}2、指针基础
1、基本概念
指针:一个对象,利用地址,它的值直接指向存在电脑存储器中另一个地方的值
内存理解:一块内存可被分为数块空间,每块空间最好存放1字节大小;每块空间对应一个编号,作为该内存单元的唯一标识
指针变量:存放变量的内存地址的变量
地址线:对于32位的机器,共有32根地址线,地址线每次寻址可产生一个电信号(+/-),故32根地址线一共可产生2^32次方个地址
指针大小:在32位机器上,地址为32个0或1组成的二进制序列,故需要通过4byte大小存储;在64位机器上,地址由64个0或1组成的二进制序列,故需要通过8byte大小存储
编址大小:对于32位机器,通过32个0或1组成的二进制序列存放地址,共有2^32种排列组合可能,又知每块内存单元存放1字节大小,故可计算得共有2^32byte = 2^22 KB = 2^12MB = 4GB编址
2、指针类型
虽然不同类型的指针存放大小相同,但不同类型的指针本质上并不相同
指针类型决定了:
[*]指针解引用时能够访问的空间的大小(int可访问4byte,char\可访问1byte)
int main()
{
double d = 3.14;
int* p = &d;
p = 0;
return 0;
}
[*]指针的步长(指针走一步的长度)
int步长为4;char步长为1;double\步长为8
int main()
{
int a = 0x11223344;
int* pa = &a;
char pc = &a;
printf("%p\n", pa);
printf("%p\n", pa + 1);
printf("%p\n", pc);
printf("%p\n", pc + 1);
return 0;
}3、野指针
野指针:指针指向的位置不可知(随机的、不正确的、没有明确限制的)
野指针成因:
[*]指针未初始化
int a;
int p = &a;
[*]数组越界访问
int arr = {0};
int* p = arr;
for(int i = 0; i < 11; i++)
{
(p++) = i;
}
[*]指针指向的内存空间释放
int test()
{
int a = 0;
return &a;
}
int main()
{
int* p = test();
return 0;
}野指针避免:
[*]指针初始化
[*]防止指针越界
[*]指针指向空间释放及时置为NULL(注:NULL本质为(void )0)
[*]检查指针指向的有效性
4、指针运算
[*]加减整数
指针与整数加减运算一般用于数组,其加减操作可理解为更改指针所指向的数组元素
int main()
{
int arr = { 1, 2, 3, 4, 5 };
int length = sizeof arr / sizeof arr;
int* p = &arr;
for (int i = 0; i < length; i++)
{
printf("%d\n", *(arr + i));
}
printf("=======================\n");
for (int i = 0; i < length; i++)
{
printf("%d\n", *(p - i));
}
return 0;
}#define N_VAL 5
int main()
{
float values;
float* vp;
for (vp = &values; vp < &values;)
{
*vp++ = 0;
}
return 0;
}
[*]加减指针
指针减指针为中间元素的个数例:三种方法实现strlen函数 //循环法
int my_strlen(char str[])
{
int count = 0;
char* p = str;
while (*p)
{
count++;
p++;
}
return count;
}
// 递归法
int my_strlen(char str[])
{
if (str)
{
return my_strlen(str + 1) + 1;
}
else
{
return 0;
}
}
// 指针间运算法
int my_strlen(char str[])
{
char* start = str;
char* end = NULL;
while (*str)
{
str++;
}
end = str;
return end - start;
}
文档来源:51CTO技术博客https://blog.51cto.com/u_15285915/3169819
页:
[1]