指针知识总结

指针=地址!!!

一、指针的解引用

        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. 除此之外所有的数组名都表⽰⾸元素的地址。

  • 17
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值