指针知识总结

       指针=地址!!!

       与普通变量不同,指针的大小是统一的。在32位操作系统下,指针的大小都是4字节,在64位操作系统下,大小为8字节。

一、指针的解引用

       对指针变量前加*号的意思是对这个指针进行解引用,也就是访问它所指向的空间。通过指针的解引用,我们就可以向使用普通变量那样使用指针。

       char* 类型的指针解引用就只能访问⼀个字节,而 int* 的指针的解引用就能访问四个字节。

二、指针加减整数

char * pc;//定义字符型指针

int * pi;//定义整形指针

        char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节。

三、void * 指针

       这种类型的指针可以⽤来接受任意类型地址。但是也有局限性, void* 类型的指针不能直接进 ⾏指针的+-整数和解引⽤的运算。

       ⼀般 void* 类型的指针是使⽤在函数参数的部分,用来接收不同类型的数据的地址。

四、const修饰指针

       变量是可以修改的,如果把变量的地址交给一个指针变量,通过指针变量也可以修改这个变量。       

int *p = &a;

int const * p = &a;

       const如果放在 * 的左边,修饰的是指针指向的内容,意思是指针指向的内容(a)不能通过指针来改变。 

int *const p = &a;

       const如果放在 * 的右边,修饰的是指针变量本身,保证了指针变量的内容(a的地址)不能修改,但是指针指向的内容(a),可以通过指针改变。

五、assert断言

       assert()的使用需要包含头文件assert.h。

       assert断言的意思是接受一个表达式作为参数,如果该表达式为真,(返回值非零),assert() 不会产生任何作用,程序继续运行。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误流 stderr 中写入⼀条错误信息,显示没有通过的表达式,以及包含这个表达式的文件名和行号。

       它不仅能自动标识文件和出问题的行号,还有⼀种无需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问题,不需要再做断言,就在 #include 语句的前面,定义⼀个宏NDEBUG 。

       assert() 的缺点是,因为引入了额外的检查,增加了程序的运行时间。

六、传值调用和传址调用

       传值调用:将值传给函数,不能在函数内部修改主函数变量。

       传址调用:将地址传给函数,可以通过函数参数接收地址,通过地址修改主函数变量。

七、数组名的理解

       数组名是首元素的地址。

       两个例外:1.sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小, 单位是字节。2.  &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。(整个数组的地址和数组首元素的地址是有区别的)

       &arr :表示整个数组的地址,&arr + 1表示跳过整个数组。

八、使用指针访问数组

 int * p = arr;

       使用arr[i]可以访问数组,使用p[i]也可以访问数组。

       *(p + i) 等价于 p[i]。

九、一维数组传参的本质

       传递的是数组首元素的地址。

十、二级指针

       存放指针的变量。

        

十一、指针数组

       存放指针的数组。

       上面的模拟的是二维数组。parr[]数组的类型是int* 。数组里面的元素是每个一维数组首元素的地址。

十二、字符指针变量

const char* pstr = "hello bit.";

       代码的是本质是把字符串 “hello bit.” ⾸字符的地址放到了pstr中。

十三、数组指针变量

int (*p)[10];

       p先和*结合,说明p是⼀个指针变量,然后指着指向的是⼀个大小为10个整型的数组。所以 p是⼀个指针,指向⼀个数组,叫 数组指针

       如果要存放整个数组的地址,就要存放在数组指针变量中。

int(*p)[10] = &arr;

十四、二维数组传参的本质

       传递的是第一行数组的地址。

十五、函数指针变量

       函数指针变量用来存放函数的地址,可以使用函数的地址调用函数。

int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;

       两种写法都可以。

       函数指针变量的使用:

int main()
{
 int(*pf3)(int, int) = Add;
 
 printf("%d\n", (*pf3)(2, 3));
 printf("%d\n", pf3(3, 5));//两种写法都可以
 return 0;
}

       输出结果

5
8

十六、typedef关键字

       typedef 是用来类型重命名的。

typedef unsigned int uint;
//将unsigned int 重命名为uint

       指针类型命名:

typedef int* ptr_t;

       但是对于数组指针和函数指针稍微有点区别。

       比如我们有数组指针类型 int(*)[5] ,需要重命名为 parr_t:

typedef int(*parr_t)[5]; //新的类型名必须在*的右边

       函数指针类型的重命名也是⼀样的,比如,将 void(*)(int) 类型重命名为 pf_t:

typedef void(*pfun_t)(int);

十七、函数指针数组

       存放函数的地址。

       函数指针数组的定义:

int (*parr1[3])();
int(*p[5])(int x, int y) = { 0, add, sub, mul, div };
//int (*指针名[元素数量]) (参数类型) = {元素1,元素2,......};

十八、回调函数

       将一个函数的地址传给另一个函数,这个函数的作用是调用地址所指向的函数,实现相应的功能。

十九、qsort函数的用法

       qsort函数是一种使用快速排序的函数。

       它需要四个参数:

       qsort(待排序数组的起始位置,元素个数,待排序数组的元素大小,函数指针)

       qsort函数的使用者得自己实现一个比较函数,用来提供比较方法。

       函数指针指向一个函数 compare(指针1,指针2),这个函数需要自己实现。

int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);//如果是p2-p1,则是降序排序。
}//          void类型的指针无法直接解引用,需要强制转换int*型。
//这个函数是由自己实现的一个函数,目的是向qsort函数提供一个比较方法。
int main()
{
	int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
	int i = 0;

	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), int_cmp);
//        首元素地址,元素个数,               元素类型     函数指针
	for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;

二十、sizeof和strlen函数的对比

       sizeof: 是操作符,计算变量所占内存内存空间大小的,单位是 字节,如果操作数是类型的话,计算的是使用类型创建的变量所占内存空间大小。

       strlen:是C语言库函数,使用需要包含库函数<string.h>。功能是求字符串长度。统计的是从 strlen 函数的参数中这个地址开始向后, ‘\0’ 之前字符串中字符的个数。 strlen 函数会⼀直向后找‘ \0’ 字符,直到找到为止,所以可能存在越界查找。

二十一、数组名的意义

       1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小。

       2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址。

       3. 除此之外所有的数组名都表示首元素的地址。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值