C语言 指针

指针

先说说指针的基本概念:
1.指针就是个变量,用来存放地址,地址唯一标识一块空间。
2.指针大小固定的4/8个字节(32位平台/64位平台)。
3.指针是有类型的,指针+1,是指加上其所指向类型的大小。

字符指针
在指针类型中,我们知道有一种指针类型为字符指针char*。
使用方式:

int main()
{
	char a='q';
	char* s=&a;
	char* str="world!!!";//我们知道C语言中是没有字符串类型的,C语言保存字符串是将字符串首元素地址保存在字符指针中,这个字符串必须以'\0'结尾代表字符串结束,称带有'\0'的字符串称为C字符串。
	return 0;
}

char* str=“world!!!”,是将字符串首元素的地址放在str中。代码中字符串放在字符常量区。若前面是char str[]=“world!!!”,则字符串是放在栈上。

来看看下面代码输出的结果是什么?

int main()
{
    char str1[] = "hello bit.";
    char str2[] = "hello bit.";
    char *str3 = "hello bit.";
    char *str4 = "hello bit.";
    if(str1 ==str2)
 printf("str1 ==  str2 \n");
    else
 printf("str1 !=  str2\n");
       
    if(str3 ==str4)
 printf("str3 ==  str4\n");
    else
 printf("str3 !=  str4\n");
  return 0;
}

在这里插入图片描述
因为str1和str2都是在栈上申请的空间,地址是不同的。只不过他们的内容恰好相等。但是str3和str4他们是指针变量,指向字符常量区的同一个字符串首元素的地址,所以相等。
**注意:**字符常量区的字符串,不能被改写。

int main()
{
    //这种是不可以的
	char* p="hello\n";
	*p='H';
	
	//建议大家可以这样写。
	const char *p="hello\n";//代表p指向的内容不能变。
	char *const p="hello\n";//代表p的指向不能变。也就是说,不能用p来遍历字符串。
}

指针数组
首先我们最应该知道的一点:指针数组是数组,是一个存放指针的数组。

int *arr1[10];//整形指针数组
int **arr2[15];//字符指针数组

那么如何来判别指针数组呢?
根据名称左右符号的优先级来判定,此处[]优先级高于*,因此是数组,所以就是指针数组。

数组指针
首先我们也应该知道的一点:数组指针是指针,是能够指向数组的指针。

int *p1[10];//指针数组
int (*p2)[10];//数组指针

判定方法与指针数组相同,看优先级。

这里我们回忆一些关于数组的知识
1.除了sizeof 和 取地址时,数组名代表的是整个数组。其他情况下数组名代表数组首元素的地址。只不过整个数组的地址和数组首元素的地址在数值上是相等的。
2.作为函数参数的数组名,降维为指向内部元素类型的指针。
3.任何数组作为函数参数,只能省略一维参数,其他维参数都不能省略。

看下面代码:

int main()
{
	int a[10];
	//int(*p)[10] = a;这样的话,只是把数组首元素的地址传给数组指针了,并不是整个数组的地址。而数组首元素的地址类型是int*型,p类型是数组指针,从而会造成类型不匹配。
	int(*p)[10] = &a;//应该取数组的地址,代表将整个数组的地址传给p,这样才是正确的。
	printf("%p\n", p);
	printf("%p\n", p + 1);
	printf("%p\n", (int)p + 1);//强转为整型,所以+1,就只是+1。
	printf("%p\n", (int *)p + 1);
	
	system("pause");
	return 0;
}

在这里插入图片描述
1.因为指针类型是数组指针,又因为指针+1,是指加上其所指向类型的大小。所以p+1相当于+40。
2.因为强转为整型,所以(int)p+1,就只是+1。
3.因为强转为指针类型,所以(int*)p+1,代表+4。

再来看看下面代码,猜猜结果:

int main()
{
	int a[10] = {0};
	printf("a=%p\n", a);
	printf("&a=%p\n", &a);

	printf("a+1=%p\n", a+1);
	printf("&a+1=%p\n", &a+1);
	return 0;
}

在这里插入图片描述
1.由结果可看出,数组名(也就是数组首元素地址)和数组地址是相同的,但是他们的意义不同。
2.数组名+1是第二个元素的地址。所以+4。
3.数组地址+1,是下一个数组的地址。所以+40。

数组指针的使用:

void print_arr1(int arr[3][5], int row, int col){}
void print_arr2(int (*arr)[5], int row, int col) {}
int main()
{
	int a[3][5]={1,2,3,4,5,6,7,8,9,10};
	print_arr1(arr, 3, 5);
	print_arr2(arr, 3, 5);
	return 0;
}

代码中两个函数参数中,接收二位数组的两种形式,都是可以的。因为我们知道数组名作为函数参数,会降维成指向数组内部元素类型的指针。 此时数组内部元素类型是数组。所以降维成数组指针类型。用print_arr2更好些。

函数指针:
首先看一段代码:

#include <stdio.h> 
void test() 
{ 
 printf("haha\n"); 
} 
int main() 
{ 
 printf("%p\n", test); 
 printf("%p\n", &test); 
 return 0; 
}

在这里插入图片描述
通过结果我们可以发现,输出的是函数的地址。那么我们怎么来保存函数地址呢?这就要用到函数指针了。

函数指针的使用:

void test()
{//操作
}
int main()
{
	void (*p)()=test;//这就是函数指针,保存的是函数的地址。
	//若指向的函数有参数,比如:test(int a),则函数指针如下
	void (*p) (int)=test;
	return 0;

注意:与数组不同的是,void *p(),不是指针函数。他就是返回值为 void *的函数。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值