C语言指针详解

本文详细介绍了C语言中的指针概念,包括取地址操作符、解引用操作、数组名的理解、指针数组、数组指针、函数指针以及字符指针的应用,帮助读者掌握C语言中这一重要概念的实际使用。
摘要由CSDN通过智能技术生成

Hello , 大家好,我是一代 ,今天给大家讲解有关指针的知识

所属专栏:C语言

一.指针的概念

在计算机中,所有的数据都是存放在存储器中的。一般把存储器中的一个字节称为一个内存单元。为了正确地访问这些内存单元,必须为每个内存单元编上号。根据一个内存单元的编号即可准确地找到该内存单元。内存单元的编号也叫做地址。既然根据内存单元的编号或地址就可以找到所需的内存单元,所以通常也把这个地址称为指针。 内存单元的指针和内存单元的内容是两个不同的概念。对于一个内存单元来说,单元的地址即为指针,其中存放的数据才是该单元的内容。

二.取地址操作符(&)和解引用操作符(*)

1.取地址操作符&

在C语言中我们通过&操作符来取出变量的地址,拿到的地址其实是一个数值,比如:0X00FFFFFF,这个数值有时候需要存储起来,那我们用什么存储呢?我们就要用存储到指针变量中去。

下面我写个代码助大家理解指针变量:

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;//取出a的地址存储到指针变量中去
	return 0;
}

其他类型的数据也是一样,比如:

char c;

char* p=&c  取出c的地址存储到指针变量中去

float a;

float* p=&a  取出a的地址存储到指针变量中去

2.解引用操作符 *

很多人有疑问,用指针指向地址有什么用呢?其实通过指针变量指向的对象的地址,我们就能通过指针带改变所指向变量的值。

下面用代码带大家去理解:

#include<stdio.h>
int main()
{
	int a = 10;
	int* p = &a;//取出a的地址存储到指针变量中去
	*p = 0;//通过解引用操作符找到a的内存,并将其改变
	return 0;
}

3.拆解指针类型

int a=10;int *p=&a; 

p左边写的是int*,*代表是指针变量,int代表p指向的整形类型的变量。

二.数组名的理解

在C语言中数组名代表的就是数组首元素的地址。那我们要怎么证明呢?其实很容易,&数组第一个元素,将其与数组名的地址都打印出来,对比就可以得出答案。

 下面代码演示一遍:

#include<stdio.h>
int main()
{
	int a[4] = { 1,2,3,4 };
	printf("%p\n", &a[0]);
	printf("%p", a);
	return 0;
}

                            

 我们发现数组名和首元素的地址一样 ,数组名就是首元素的地址,(注:arr[i]相当与*(arr+i),但其实还有两个例外:

1.sizeof(数组名):sizeof中单独放数组名,这里的数组名就不表示首元素地址,表示的是整个数组,计算的是整个数组的大小,单位是字节。

如:

int arr[10];

printf("%d",sizeof(arr));

打印出来的答案是40,而不是地址的大小。(注:地址的大小为4或8个字节,大小跟平台大小有关)

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

三.指针的运用

1.指针数组

指针数组是用来存放地址的,其每个元素都是地址,如下图:

那指针数有什么用呢?其可以用来模拟二维数组。

下面我们用指针数组模拟二维数组:

#include <stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };
	//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
	int* parr[3] = { arr1, arr2, arr3 };
	int i = 0;
	int j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", parr[i][j]);
		}
		printf("\n");
	}
}

parr[i]访问的是parr的元素,parr[i]找到的数组元素指向了整形一维数组,parr[i][j](相当于*(*(parr+i)+j)  )就是整形一维数组中的元素。

2.数组指针

数组指针变量是用来存放数组地址的。其和指针数组不同,其书写模式为int (*p)[10],解释:p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个大小为10个整型的数组。所以 p是⼀个指针,指向⼀个数组,叫数组指针。(注:[ ]的优先级比*高,所以加个()来保证p和*结合)

如果要存放某个数组的地址,就可以写成int arr[10]  ;   int(*p)[10] = &arr  ;

数组指针经常用于接收二维数组的首地址(也就是第一行的地址)。

如:

#include <stdio.h>
void test(int(*p)[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 ", *(*(p + 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;
}

其中arr表示二位数组第一行的地址,其类型为int [5],用数组指针来接受,数组指针类型为int *[5] 。

 3.函数指针

如果我们将函数的地址存起来,我们就可以用到函数指针。(注:函数名就是函数的地址,也可以通过&函数名来获得函数的地址)

函数指针变量和数组指针用起来没有太大区别,如:

void test()
{
	printf("hello");
}
void (*pf1)() = test;
int add(int x, int y)
{
	return x + y;
}
int (*pf2)(int, int) = add;
int (*pf3)(int x, int y) = add;//x和y可以省略

4.函数指针数组

函数指针数组的书写形式为int (*parr[3]) (),借助函数指针数组,我们可以实现转移表。

#include<stdio.h>
void meau()
{
	printf("********************\n");
	printf("***1.Add    2.Sub***\n");
	printf("***3.Mul    4.Div***\n");
	printf("*****  0.exit  *****\n");
	printf("********************\n");
}
int Add(int x, int y)
{
	return x + y;
}
int Mul(int x, int y)
{
	return x * y;
}
int Sub(int x, int y)
{
	return x - y;
}
int Div(int x, int y)
{
	return x / y;
}
int main()
{
	int input = 0;
	int x = 0;
	int y = 0;
	int(*parr[5])(int, int) = { 0,Add,Sub,Mul,Div };
	do
	{
		meau();
		printf("请选择:>");
		scanf("%d", &input);
		if (input >= 1 && input <= 4)
		{
			printf("请输入两个操作数:>");
			scanf("%d%d", &x, &y);
			int ret = parr[input](x, y);
			printf("%d\n", ret);
		}
		else if (input == 0)
		{
			printf("退出\n");
		}
		else
		{
			printf("选择错误\n");
		}
	} while (input);
	return 0;
}

 5.字符指针变量

我们经常可以碰到类似于char * str="abcd";的代码,我们很容易将其认为是把字符串“abcd”放到字符指针str中,但本质是把字符串的首元素地址放到了str中。

这里有一道《剑指offer》中的笔试题:

#include <stdio.h>
int main()
{
	char str1[] = "hello bit.";
	char str2[] = "hello bit.";
	const char* str3 = "hello bit.";
	const char* str4 = "hello bit.";
	if (str1 == str2)
		printf("str1 and str2 are same\n");
	else
		printf("str1 and str2 are not same\n");

	if (str3 == str4)
		printf("str3 and str4 are same\n");
	else
		printf("str3 and str4 are not same\n");
	return 0;
}

注:const如果放在*的左边,修饰的是指针指向的内容,保证指针指向的内容不能通过指针来改变。 但是指针变量本⾝的内容可变。const如果放在*的右边,修饰的是指针变量本⾝,保证了指针变量的内容不能修改,但是指针指向的内容,可以通过指针改变。

如:

const int *p=&n;

const 在*左边,*p就不能改变

*p=20这个操作是不行的,但p=&m可以 

 这里str1和str2并不相同,因为c/c++中会把常量字符串存储到内存单独的一个内存区域,当⼏个指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存。但是⽤相同的常量字符串去初始 化不同的数组的时候就会开辟出不同的内存块,所以str1和str2不相同。但str3和str4前面加了const, 其指向的数据位于常量区,其内容不可被改变,所以str3和str4相同。

以上如有错误,欢迎各位佬们指正

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  

  • 67
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 33
    评论
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值