C语言 指针笔记

前言

推荐宝藏up视频C语言指针,up讲的超级好!本文便是基于up视频整理的C语言指针笔记。笔记仅用于复盘,真正学懂还得看up视频!

指针的概念

int *p = &a;
	*p = 100;
  • 在64位操作系统里面,指针占8字节
  • 星号的两种含义:
    1、定义的时候(前面有类型),表示后面的变量是指针
    2、使用的时候:表示取值(取指针指向的内存空间的值)
  • int*和char*步长(单位)不一样,指针加一之后的结果不同,取决于指针类型,如int为4字节,char为1字节

*px++和(*px)++

练习:

int x = 3, y = 0, *px = &x;
y = *px +5;  //y等于8
y = ++*px;   //y等于4
y = *px++;   //先把*px(3)赋值给y,再把px+1(变成野指针)
  • *px++和(*px)++是有区别的,前者是对px加加,后者对*px加加

const的用法

void f()
{
	int num;
	const int *p1 = # // const修饰*p1 即num
	//(*p1)++;
	p1++;
	
	int  *const p2 = #// const修饰p2
	//p2++;
	(*p2)++;
	
	const int *const p3 = #// 即修饰了p3,也修饰了*p3,二者均不能修改
}
  • const就近原则,修饰哪个,哪个就不能改

野指针和空指针

int main()
{
	int *p = NULL;
	*P = 100;			// 段错误,访问了不能访问的内存
	
	// 如何合法使用内存
	// 1、系统分配的内存
	int a;
	int *p1 = &a;

	// 2、用户申请的内存(堆内存)
	char* str = (char*)malloc(32);
	free(str); 	// 释放内存,如果不释放,内存泄漏
	str = NULL;
	
	return 0;
}
  • 三种合法使用内存的方法:
    1、使用系统分配的内存(定义一个变量,把变量的地址赋值给指针)
    2、用户使用malloc自己申请堆内存
    3、将字符串赋值给指针,字符串存放在只读数据区
  • 申请堆内存注意事项:
    1、使用完后释放内存,避免内存泄漏
    2、释放完后,将指针赋值为空,否则指针会指向被释放掉的内存,成为野指针。(空指针是个可控指针)

指针和数组

int main()
{
	int a[5] = {1,2,3,4,5};
	int *p = a;
}
  • 从使用的角度,指针和数组可以相互替换
  • 通过指针的形式访问数组,a[i]等价于*(a+i)

指针和数组的区别

int main()
{
	char str[32] = "helloworld";
	char *p = "helloworld";
	
	//str++; // 数组名是常指针(地址常量)不能修改。
	p++;	 //  指向下一个元素 

	str[0] = 'x';
	//p[0] = 'x'; // 字符串常量存在只读数据区里面,不能修改
	
}
  • 数组名是常指针(地址常量)不能修改。数组名不能++,在定义数组的时候已经给数组分配的空间,数组名++代表把原先分配好的数组地址整体往后移动,这是不被允许的。
  • 数组定义的字符串存放在栈空间,而指针指向的字符串常量在只读数据区,前者可修改,后者不能修改。
  • sizeof(str)代表整个数组的长度,sizeof(p)代表指针长度
void f(int a[])
{
	printf("%lu\n",sizeof(a)/sizeof(a[0]));// 2
}
int main()
{
	int a[10] = {0};
	printf("%d\n",sizeof(a)/sizeof(a[0]));// 10
	f(a);
	return 0;
}
  • 特别注意!数组名作为参数传递之后会变成指针,f()函数中的sizeof(a)在64位操作系统里面,是a这个指针的大小,即8字节。而主函数中的sizeof(a)则代表a这个数组的大小,即10字节。

练习:

int a[5] = {1,2,3,4,5};

int *p1 = (int*)(&a + 1);	
int *p2 = (int*)((int)a + 1);
int *p3 = (int*)(a + 1);
//假设a[0]地址为0x100,p1[0],p2[0],p3[0]的值分别为多少?
// &a+1为0x114 p1[0]就是0x114那个地址对应的值
// (int)a+1为0x101 p2[0]就是0x101地址对应的值
// a+1为0x104,p3[0]是0x104对应的值,即2,只有这个是正常的写法 
  • &a表示整个数组的地址
  • a表示数组首元素的地址
  • (int*)代表强转,比如&a + 1本来指向从0x114开始的5个字节的整体,强转之后就只指向0x114那一个字节

指针数组

int* p[5]本质是一个数组,数组的每个元素都是指针类型

数组指针

int (*p)[5]本质是一个指针,该指针指向数组

指针和二维数组

int a[3][4]

  • a表示数组首行地址,一次加一行即16字节
  • a[0]表示首行首元素的地址, 一次加一个元素即占4字节
  • &a表示数组地址 ,一次加一个数组即占48字节
  • 行:sizeof(a) / sizeof(a[0]) 即48/16 = 3
  • 列:sizeof(a[0]) / sizeof(a[0][0]) 即16/4 = 4

数组指针表示二维数组:int(*p)[4] = a;

  • *(p+i)代表第i行首元素的值
  • *(p+i)+j代表第i行第j列的地址
  • *(*(p+i)+j)代表第i行第j列元素的值

指针数组表示二维数组:int* p[3] = {a[0],a[1],a[2]};

  • p[i][j]等价于a[i][j]

指针表示二维数组:int* p = a[0];

  • 当成一维数组来处理
int *p = a[0];
for (i = 0; i < 12; i++)
{
	printf("%d ",p[i]);
}

总结

  • &a表示指向二维数组的指针,步长为整个数组
  • a表示二维数组名,指向一维数组a[0],即第0行首地址,步长为数组的一行
  • a[0],*(a+0),*a表示第0行第0列元素地址
  • a+1,&a[1]表示第1行首地址
  • a[1],*(a+1)表示第1行第0列元素地址
  • a[1]+2,*(a+1)+2,&a[1][2]表示第1行第2列元素地址
  • *(a[1]+2),*(*(a+1)+2),a[1][2]表示第1行第2列元素的值
  • 理解:一级地址是元素地址(a[0]),二级地址是行地址(a),三级地址是整个数组地址(&a)

指针和字符串

int main()
{
	char *string[]={"abc","123"};
	//printf("%s\n",string);  // 报错
	return 0;
}
  • string是个指针数组,本质是个数组,里面存放的是指针

指针和函数

函数指针

void f1()
{
	printf("helloworld\n");
}

int add(int x, int y)
{
	return x+y;
}

typedef int (*T)(int,int);// 声明一个新的类型T T表示函数指针类型

int main()
{
	void (*p)();  // 定义函数指针
	p = f1;
	p();  // 通过函数指针调用函数 等价于f1()

	int (*q)(int,int) = add;
	printf("%d\n",q(1,2));

	T q1 = add; // 等价于int (*q)(int,int) = add;
	return 0;
}

指针函数

char *init()  // 指针函数
{
	//char str[32] = {0};   // 栈内存在函数运行结束之后会被释放掉!
	char *str = (char *)malloc(128);
	
	return str;
}

int main()
{
	char *s = init();
	
	strcpy(s,"hello");
	
	free(str);
	
	str = NULL;
	
	return 0;
}
  • 函数指针和指针函数的区别:

  • 1、int (*p)()定义的是一个变量,表示p是一个指向函数入口的指针变量,该函数的返回值是整型,(*p)两边的括号不能少

  • 2、int *p()则不是变量声明而是函数声明,说明p是一个指针型函数,返回值是一个整型变量的指针,*p两边没有括号

  • 函数指针可以用作回调函数,把函数名作为另一个函数的参数,以此来修改函数的功能。

复杂类型声明(右左法则)

int*(*(*fp)(int))[10];

fp是一个指针,指向一个函数,该函数有一个int类型的参数,返回值是指针,该指针指向一个有是个元素的数组,数组里的元素是int*类型。

int *(*(*array[5])())();

array是一个指针数组,有5个元素,每个元素都是指针,指向一个函数,该函数没有参数,返回值一个指针,指针又指向一个没有参数的函数,返回值为int*类型指针。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值