c语言指针详解

指针的定义

指针相对于一个内存单元来说,指的是单元的地址,该单元的内容里面存放的是数据。在C语言中,允许用指针变量来存放指针,因此,一个指针变量的值就是某个内存单元的地址或称为某内存单元的指针。简单来说,指针就是用来存放地址的。
讲解的内容有:
字符指针
整形指针
数组指针
函数指针
指针数组
指向指针数组的指针
函数指针数组
指向函数指针数组的指针

在32位系统下,所有的指针都是4个字节大小。
在64位系统下,所有的指针都是8个字节大小。

字符指针

我们先来看到以下代码。
结果会是什么呢?

#include<stdio.h>
int main()
{
	char c = 'w';
	char* p = &c;
	printf("%p\n%p\n", &c, p);
}

在这里插入图片描述

可以看到p存放了c的地址,即p是一个字符指针,
*是解引用操作,与指针相互使用。

#include<stdio.h>
int main()
{
	char c = 'w';
	char* p = &c;
	*p = 'c';
	printf("%c\n%c\n", c, *p);
}

c里面的值通过对指针p的访问改成了c,这是间接访问,即通过地址对其中的值进行改变。

整形指针

整形指针和字符指针类似,不过一个指向整形,一个指向字符。

#include<stdio.h>
int main()
{
	int n = 10;
	int* p = &n;
	*p = 8;
	printf("%p\n%p\n", &n, p);
	printf("%d\n%d\n", n, *p);
}

在这里插入图片描述
结果是类似的。
到了这里,有没有想到一个问题:
既然这些指针的大小都是一样的,为什么还需要分类型呢?
看到以下代码

#include<stdio.h>
int main()
{
	int n = 10;
	char* p = &n;
	*p = 1000;
	printf("%d\n", n);
	
}

这个代码强行让字符指针存放的是整形变量的地址,然后再进行赋值。
在这里插入图片描述
结果却输出了232,对于这个结果,我们可以查看内存
在这里插入图片描述
在这里插入图片描述
在这里我们看到,有第一行有四列,也就是四个字节,只有最前面的内存被改变了。
原来,字符指针只能操作一个字节的内容,相应的,整型指针可以操作四个字节的内容。

数组指针

首先我们要了解指针和数组

#include<stdio.h>
int main()
{
	int arr[10] = { 0 };
	int* p = arr;
	printf("%p\n%p\n", p, arr);
	
}

在这里插入图片描述
这个结果我们发现,数组名其实就是一个指针,这个指针指向的是数组首元素的地址。也就是说,像下面的传参其实是等价的。

void test(int arr[])
{

}
void test1(int* arr)
{

}

在了解以上内容后,可以引申到数组指针。
什么是数组指针?从字面意思来看,这就是指向数组的指针。

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

arr arr+1 &arr+1的结果并不相同
arr指向数组首元素的地址
arr+1指向数组第二个元素的地址
而&arr+1却是一个野指针,已经越界。(但并没有访问,所以编译器不会报错)说明&arr+1跨过的位置就是一个数组的大小。
野指针:
没有初始化的指针
数组越界
局部变量的返回值,但局部变量已经被销毁。

int main()
{
	int arr[10] = { 0 };
	int(*p)[10] = &arr;
}

[]的优先级比*要高,将 *与p结合,说明这是一个指针,( *p )[10]说明这是一个数组指针,数组里的每个元素是int。

#include<stdio.h>
void test(int* arr,int x)
{
	for (int i = 0; i < x; i++)
	{
		printf("%d ", arr+i);
	}
}
int main()
{
	int arr[10] = { 0 };
	test(&arr,10);
}

像这样的传参并不好,因为test传递的是整个数组的地址,而我们却用
整型指针来接受,这会让人产生误解。而且结果与我们预期的也不相同。在这里插入图片描述

#include<stdio.h>
void test(int* arr,int x)
{
	for (int i = 0; i < x; i++)
	{
		printf("%d ", *((arr + 0) + i));
	}
}
int main()
{
	int arr[10] = { 0 };
	test(&arr,10);
}

在这里插入图片描述

对于数组指针,我们要这样进行访问,我们把它看成二维数组,只不过这个二维数组只有一行,arr+0就是找到第一行,然后再进行访问。
当然,这对于一维数组来说并不好用,但这很适用于二维数组

#include<stdio.h>
void test(int* arr,int x)
{
	for (int i = 0; i < x; i++)
	{
		for (int j = 0; j < x; j++)
		{
			printf("%d ", *((arr + i) + j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[10][10] = { 0 };
	test(&arr,10);
}

在这里插入图片描述
像int* 这样的传参并不好,如果将参数换成这样:
就可以知道这是一个数组指针。

#include<stdio.h>
void test(int(*arr)[10],int x)
{
	for (int i = 0; i < x; i++)
	{
		for (int j = 0; j < x; j++)
		{
			printf("%d ", *(*(arr + i) + j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[10][10] = { 0 };
	test(&arr,10);
}

在这里插入图片描述

指针数组

指针数组是用来存放指针的,int* p[10] p先与[]结合,说明这是一个数组,数组里的每个元素都是int*。

#include<stdio.h>

int main()
{
	int arr[10];
	int* p[10] = { arr,arr + 1,arr + 2,arr + 3,arr + 4,arr + 5 ,arr+6,arr+7,arr+8,arr+9};
	for (int i = 0; i < 10; i++)
	{
		printf("%p ", p[i]);
	}
	printf("\n");
	for (int i = 0; i < 10; i++)
	{
		printf("%p ", arr+i);
	}
}

在这里插入图片描述

指向指针数组的指针

int* (*p)[10] 与p先结合,说明这是个指针,再与[]结合,说明这个指针指向一个数组,里面的每个元素是int

函数指针

函数指针,顾名思义,这就是指向函数的指针

#include<stdio.h>
void test(int(*arr)[10],int x)
{
	for (int i = 0; i < x; i++)
	{
		for (int j = 0; j < x; j++)
		{
			printf("%d ", *(*(arr + i) + j));
		}
		printf("\n");
	}
}
int main()
{
	int arr[10][10] = { 0 };
	void (*p)() = &test;
	p(&arr, 10);
}

在这里插入图片描述
这里的p就是函数指针,指向test。
而在使用p访问这个函数的时候(*p)(&arr,10)这样也是可行的,为了简便可以不用(*p)(&arr,10)而直接使用p(&arr,10)。

函数指针数组

函数指针数组就是用来存放函数指针的

int (*parr1[10])();
#include <stdio.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 div(int a, int b)
{
           return a / b;
}
int main()
{
     int x, y;
     int input = 1;
     int ret = 0;
     int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
     while (input)
     {
          printf( "*************************\n" );
          printf( " 1:add           2:sub \n" );
          printf( " 3:mul           4:div \n" );
          printf( "*************************\n" );
          printf( "请选择:" );
      scanf( "%d", &input);
          if ((input <= 4 && input >= 1))
         {
          printf( "输入操作数:" );
              scanf( "%d %d", &x, &y);
              ret = (*p[input])(x, y);
         }
          else
               printf( "输入有误\n" );
          printf( "ret = %d\n", ret);
     }
      return 0;
}

函数指针数组经常用于代码量多的时候,在代码量多的时候,使用韩式指针数组可以大大简化代码。

指向函数指针数组的指针

套娃套娃再套娃,指针非常灵活,也不易使用,如果我们对它了解很深刻,指针会非常好用。

void test(const char* str)
{
 printf("%s\n", str);
}
int main()
{
 //函数指针pfun
 void (*pfun)(const char*) = test;
 //函数指针的数组pfunArr
 void (*pfunArr[5])(const char* str);
 pfunArr[0] = test;
 //指向函数指针数组pfunArr的指针ppfunArr
 void (*(*ppfunArr)[10])(const char*) = &pfunArr;
 return 0;
}
  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值