目录
1、sizeof和strlen
2、函数形参(很重要)
2.1传值调用
2.2传址调用
3、函数的嵌套调用和链式访问
4、隐式类型转换
4.1整型提升
4.2算术转换
5、野指针
6、const
7、写一个函数返回参数二进制中 1 的个数。
各位朋友大家好呀!在学c语言的时候,总会遇到些零碎的知识点或者名词,每个知识点单独水一篇脸上挂不住,所以缝合成一篇发布了,赶紧来查漏补缺吧。
1、sizeof和strlensizeof是关键字,以数组为例,'\0'也会被计算,所以不要管数组里边放了什么数据,直接数元素个数即可,再乘数据类型大小,单位是字节。
strlen是库函数,遇到'\0'就停止,不计算'\0'。
#include
#include
int main()
{
char arr[] = "abcdef";
printf("%zu %zu", sizeof(arr), strlen(arr));//输出7和6。
return 0;
}
2、函数形参(很重要)
形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有效。
2.1传值调用传值调用时,形参是实参的一份临时拷贝,形参的改变不会改变实参。
2.2传址调用可以通过传入实参的地址,在函数内部 *** 纵实参。
传址调用的总结:先明确想要修改的值是什么类型,设定的形参类型需要比修改类型多一颗*哦!
举例:
1、冒泡排序函数需要通过修改数组内的元素,从而达到排序的目的。那么我们需要传入一级指针。
2、无头单链表的头插,需要改变单链表的头指针,所以要传入二级指针。
3、函数的嵌套调用和链式访问 3.1函数的嵌套调用函数里边调用函数。
3.2函数的链式访问把一个函数的返回值作为另外一个函数的参数。
4、隐式类型转换隐式转换指的是不需要用户干预,编译器私下进行的类型转换行为。很多时候用户可能都不知道发生了哪些转换。
4.1整型提升表达式的整型运算要在CPU的相应运算器件内执行,CPU内整型运算器(ALU)的 *** 作数的字节长度一般就是int的字节长度,同时也是CPU的通用寄存器的长度。
所以char和short类型在运算时,会先转换为int或unsigned int参与运算,运算完成后将多余的二进制位截断,重新储存至原类型内。
整型提升的方式1、有符号数据类型高位补符号位
2、无符号数据类型高位补0
整型提升的例子先来看一段代码
4.2算术转换当程序运行到char c=a+b时,将会发生整型提升。
125在内存中的补码是01111101
5在内存中的补码是00000101
整型提升后125和5的补码分别是:
00000000000000000000000001111101
00000000000000000000000000000101
相加所得c的补码:
00000000000000000000000010000010
把c截断的补码:10000010
以%d的形式打印c,再次发生整型提升得到c的补码:
11111111111111111111111110000010
c的原码:
10000000000000000000000001111110(-126)
两个不同类型的 *** 作数在运算时,排名较低的类型将被转换为排名较高的数据类型。以下是数据类型的排名。
long double
double
float
unsigned long int
long int
unsigned int
int
注意:若将排名较高的数据类型转换为排名较低的数据类型,将会丢失精度。
float f = 3.14;
int num = f;//隐式转换,会有精度丢失
5、野指针
野指针:指针指向的位置是不可知的。
5.1野指针的成因 1、指针未初始化#include
int main()
{
int *p;//局部变量指针未初始化,默认为随机值
*p = 20;
return 0;
}
2、指针越界
#include
int main()
{
int arr[10] = { 0 };
int* p = arr;
for (int i = 0;i < 12;i++)
{
*(p++) = i;//程序报错
}
return 0;
}
3、指针指向的空间销毁/释放
#include
int* test()
{
int a = 10;
return &a;
}
int main()
{
int*p = test();//由于a在出了函数范围即被销毁,可以认为此时p是野指针
if (p != NULL)
{
printf("%d\n", *p);//
}
return 0;
}
动态内存管理中,需要将堆区的指针及时置空(后续文章进行讲解)
5.2如何规避野指针1. 指针初始化 2. 小心指针越界 3. 指针指向空间释放即使置 NULL 4. 避免返回局部变量的地址 5. 指针使用之前检查有效性6、const
const int* p=arr[10];//保护arr不被修改(可用下一级指针进行更改)
int* const p=arr[10];//保护指针p不被修改(可用下一级指针进行更改)
const int* const p=arr[10];//保护指针p和数组都不可被修改(可用下一级指针进行更改)
7、写一个函数返回参数二进制中 1 的个数。
7.1除2法
int count_num_of_1(unsigned int n)
{
int count = 0;
while (n)
{
if ((n % 2) == 1)
{
count++;
}
n /= 2;
}
return count;
}
注意形参必须是unsigned整型,可以兼顾正负数的二进制位1的统计。
7.2使用n &(1<int count_num_of_1(int n)
{
int i = 0;
int count = 0;
for (i = 0; i < 32; i++)
{
if ((n &(1<
让1的二进制位分别左移0-31位后与n按位与,即可得到n的二进制位的1的个数。左移较右移的优点:不用考虑当前编译器是算术右移还是逻辑右移。
7.3使用n = n & (n - 1)int count_num_of_1(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
让n与n-1按位与,计算出n的二进制位的个数。类似抽丝剥茧,把n的二进制位上的1,从低位到高位,层层统计出来。
关注!点赞!评论!收藏!关注!点赞!评论!收藏!关注!点赞!评论!收藏!关注!点赞!评论!收藏!关注!点赞!评论!收藏!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)