指针有关知识整理

Part1

1、指针的基本概念

指针变量也是一种变量,这种变量是用来存放地址的,指针变量也被简称为指针。

指针变量的大小:32位条件下4字节,64位条件下为8字节。

2、指针变量类型的意义

结论:指针的类型决定了对指针解引用的时候有多大的权限(即一次可以操作几个字节),比如,char*类型的指针解引用一次只能访问一个字节,int*的指针解引用就能访问四个字节。

指针+-整数:指针的类型决定了指针向前或者向后走一步有多大(距离)。

3.void*指针

可以理解为无具体类型的指针(泛型指针),可以用来接受任意类型的地址。

局限性:不能直接进行指针的+-整数和解引用的运算。

应用:一般使用在函数参数的部分,用来接收不同数据类型的地址,可以实现泛型编程的效果。

4.const修饰指针

总结:

(1)const如果放在*左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变,但是指针变量本身的内容可变。

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

5.指针运算

(1)指针+-整数:加或减去所n个指向类型的字节数。

(2)指针-指针:结果为两指针间所占的此类型的元素个数。

(3)指针的关系运算:

#include<stdio.h>


int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 , 10 };
	int* p = &arr[0];
	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);
	while (p < arr + sz)
	{
		printf("%d", *p);
		p++;
	}
	return 0;
}

6.野指针

概念:野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的。

6.1野指针成因

(1)指针未初始化;

(2)指针越界访问;

(3)指针指向的空间释放;

6.2如何规避野指针

(1)指针初始化;

(2)小心指针越界;

(3)指针变量不再使用时,及时置NULL,指针使用前检查有效性:

#include<stdio.h>

int main()
{
	int arr[10] = { 1, 2, 3, 4, 5, 6, 7,  8, 9, 10 };
	int* p = &arr[0];
	for (int i = 0; i < 10; i++)
	{
		*(p++) = i;
	}
	//此时p已经越界
	p = NULL;
	p = &arr[0];
	if (p != NULL)
	{
		//...
	}
	return 0;
}

(4)避免返回局部变量的地址;

7.assert断言

  assert.h 头⽂件定义了宏 assert() ,⽤于在运⾏时确保程序符合指定条件,如果不符合,就报
错终⽌运⾏。这个宏常常被称为“断⾔”。
assert(p != NULL);

上⾯代码在程序运⾏到这⼀⾏语句时,验证变量 p 是否等于 NULL 。如果确实不等于 NULL ,程序继续运⾏,否则就会终⽌运⾏,并且给出报错信息提⽰。

assert() 宏接受⼀个表达式作为参数。如果该表达式为真(返回值⾮零), assert() 不会产⽣
任何作⽤,程序继续运⾏。如果该表达式为假(返回值为零), assert() 就会报错,在标准错误
  流 stderr 中写⼊⼀条错误信息,显⽰没有通过的表达式,以及包含这个表达式的⽂件名和⾏号。  
assert() 的使⽤对程序员是⾮常友好的,使⽤ assert() 有⼏个好处:它不仅能⾃动标识⽂件和
出问题的⾏号,还有⼀种⽆需更改代码就能开启或关闭 assert() 的机制。如果已经确认程序没有问
  题,不需要再做断⾔,就在 #include <assert.h> 语句的前⾯,定义⼀个宏 NDEBUG 。
#define NDEBUG
#include <assert.h>

然后,重新编译程序,编译器就会禁⽤⽂件中所有的 assert() 语句。如果程序⼜出现问题,可以移

  除这条 #define NDBUG 指令(或者把它注释掉),再次编译,这样就重新启⽤了 assert() 语
assert() 的缺点是,因为引⼊了额外的检查,增加了程序的运⾏时间。
⼀般我们可以在 Debug 中使⽤,在 Release 版本中选择禁⽤ assert 就⾏,在 VS 这样的集成开
发环境中,在 Release 版本中,直接就是优化掉了。这样在debug版本写有利于程序员排查问题,
  在 Release 版本不影响⽤⼾使⽤时程序的效率。            
Part2
1.数组名的理解
结论:数组名就是数组首元素(第一个元素)的地址。
两个例外:
(1)sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
(2)&数组名,取出的是 整个数组的地址。
2.一维数组传参的本质
结论:数组传参本质上传递的是数组首元素的地址;
一维数组传承,形参的部分可以写成数组的形式,也可以写成指针的形式。
3.二级指针
即指向一级变量地址的指针。
4.指针数组
用于存放指针的数组
Part3
1.数组指针变量
即存放的是数组的地址,能够指向数组的指针变量。
int (*p)[10];
解释:p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以p是⼀个指针,指向⼀个数组,叫数组指针。
注意:[ ]的优先级要⾼于*号的,所以必须加上()来保证p先和*结合。
2.二位数组传参的本质
传递的是地址,传递的是第一行这个一维数组的地址。
#include <stdio.h>
void test(int a[3][5], int r, int c)
{
    int i = 0;
    int j = 0;
    for(i=0; i<r; i++)
    {
        for(j=0; j<c; j++)
        {
        printf("%d ", a[i][j]);
        }
        printf("\n");
    }
}
int main()
{
    int arr[3][5] = {{1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7}};
    test(arr, 3, 5);
    return 0;
}

3.函数指针变量

函数指针类型解析:

typedef关键字:

⽐如我们有数组指针类型 int(*)[5] ,需要重命名为 parr_t ,那可以这样写:
typedef int(*parr_t)[5]; //新的类型名必须在*的右边

应用:简化代码

简化前:

void (*signal(int , void(*)(int)))(int);

简化后:

typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);

4.函数指针数组

储存函数指针的数组。

应用:转移表

#define _CRT_SECURE_NO_WARNINGS

#include<stdio.h>
#include<stdlib.h>

int add(int a, int b)
{
	return a + b;
}

int sub(int a, int b)
{
	return a - b;
}

int mul(int a, int b)
{
	return a * b;
}

int d(int a, int b)
{
	return a / b;
}

int main()
{
	int input = 0;
	int (*p[5])(int, int) = { 0, add, sub, mul, d };
	do
	{
		int ret = 0;
		int a = 0;
		int b = 0;
		printf("1.add\n2.sub\n3.mul\n4.div");
		scanf("%d", &input);
		scanf("%d %d", &a, &b);
		if (input >= 1 && input <= 4)
		{
			ret = p[input](a, b);
			printf("%d\n", ret);
		}
		else if(input == 0)
		{
			printf("exit\n");
		}
		else
		{
			printf("again\n");
		}
		system("pause");
		system("cls");
	} while (input);
	return 0;
}

5.回调函数

通过函数指针调用的函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值