c语言--指针进阶(1)(适用考研计算机C语言学习)

本章内容

  • 字符指针

  • 指针数组

  • 数组指针

  • 数组参数

  • 指针参数

回忆指针

1.指针就是一个变量,用来存放地址,地址唯一标识一块内存空间

2.指针的大小是固定的4/8(个字节32平台/64位平台)

3.指针是种类型。指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限

4.指针的运算

字符指针

在指针类型中我们知道有一种指针类型为字符指针char*

一般使用

#include<stdio.h>
int main()
{
	char ch='w';
	char* pc =&ch;
	*pc='w';
	return 0;

}

 还有一种写法

//还有一种方法
#include<stdio.h>
int main()
{
	char arr[]="abcedf";
	char* pc =arr;
	printf("%s\n",arr);
	printf("%s\n",pc);
	return 0;
}

 运行结果:

 另一种写法:


#include<stdio.h>
int main(){
	char* p="abcdef";  //其实是把首字母地址赋给p
	                   //abcdef是常量字符串
	printf("%c\n",*p);
	printf("%s\n",p);
	return 0;

}

 

 注意字符串常量不可以改变,所以第三行最好前面加const

const char* p="abcdef"; 

 练习

 

 原因是两个不同数组,两个不同数组名肯定存放不同地址,所以打印的地址肯定不同

图解:

 如果改成

 

 原因是字符串abcdef是常量字符串,,常量字符串不可以修改,所以内存中只有一份这个字符串abcdef,指针存放首字母地址,指针存放的这两个字符串相同,所以指针指向相同地址

图解

 

指针数组

指针数组的定义

定义:指针数组是个数组,是一个存放指针的数组

如图解释什么是指针数组

 指针数组的简单使用

//指针数组

#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[]={arr1,arr2,arr3};
	int i =0;
	for(i=0;i<3;i++)
	{
		int j=0;
		for(j=0;j<5;j++)
		{
			printf("%d",*(parr[i]+j));
		}
		printf("\n");
		
	}
	return 0;
}

 运行结果

 图解

 

数组指针

数组指针的定义

数组指针是个指针,指向数组的指针,存放数组的地址

 

 int *p1[10];  //存放指针的数组

int (*p2)[10];  //存放数组的指针

解释:p2先和*结合,说明p2是一个指针变量,然后指着指向的是一个大小为十个整型的数组,所以P是一个指针指向一个数组脚数组指针。

 分析意义:

 

 

 

          &arr存放的是数组的地址,不是数组首元素的地址

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

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

arr+1:跳过一个元素

&arr+1:跳过一个数组的大小

运行结果:


 

 数组指针的用法:(一般在二维数组里面会用到)

首先最基本的用二维数组作为参数访问

#include<stdio.h>
//参数是数组的形式
void print1(int arr[3][5],int x,int y)
{
	int i=0;
	int j= 0;
	for(i=0;i<x;i++)
	{
		for(j=0;j<y;j++)
		{
			printf("%d ",arr[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}};
	print1(arr,3,5);//传数组,传行,传列
	return 0;
}

 运行结果:

 

 分析:

我们都知道数组名arr是首元素的地址,那对于二维数组的首元素的地址是谁呢?

应该把二维数组arr想象成一维数组,把第一行当作第一个元素,把第2行当作第2个元素,把第3行当作第3个元素,即把第几行当作第几个元素,

那么这里的数组arr其实就有三个元素

所以这里的arr代表第一行的地址

第1行又是个一维数组,里面又有5个元素,每个元素是int型

所以这样我们有了下面这个版本,

使用参数使用数组指针的方式

下面开始真正使用数组指针来访问:

#include<stdio.h>
//参数是指针的形式
void print2(int (*p)[5],int x,int y) //参数int (*p)[5]指向第一行的元素的地址
{
	int i=0;
	for(i=0;i<x;i++)
	{
		int j= 0;
		for(j=0;j<y;j++)
		{
			printf("%d ",*( *(p+i)+j));  //打印每行
		}
		printf("\n");  //打印完一行换行
		       
		//(p+i)就是跳过i行 找到了某行   而*(p+i)解引用相当于找到具体那一行,其实就是找到了这行的数组名,是第一行的地址,因为第一行本身是个数组,我们把他想象成数组的第一个元素来看,而我们在一维里面知道解引用是找到里面元素,,所以这里二维里面解引用就是用一行地址代表元素
		//  *(p+i)+j  :    *(p+i)再加j 找到i行的里面某个元素j的地址
		//再解引用,*( *(p+i)+j),找到i行j列元素
	}

}
int main()
{
	int arr[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};
	print2(arr,3,5);
	return 0;
}

一步步分析print2()函数代码:

(1)(p+i)就是跳过i行 找到了某行  

(2)而*(p+i)解引用相当于找到具体那一行,其实就是找到了这行的数组名,是第一行的地址

(因为第一行本身是个数组,我们把他想象成数组的第一个元素来看,而我们在一维里面知道解引用是找到里面元素,所以这里二维里面解引用就是用一行地址代表元素)

(3)*(p+i)+j  :    *(p+i)再加j 找到i行的里面某个元素j的地址

(4)再解引用,*( *(p+i)+j),找到i行j列元素

运行结果:

 区分下面代码的意思

 

用图解释  int(*parr3[10])[5]

 

 

回忆巩固

[]比*优先级高,()比[]优先级高

int *ch[5] ;   ch是数组

int (*ch)[5];  ch是指针

    int(*)[5]就是数组指针类型

 

数组参数和指针参数

在写代码时候难免要把【数组】或者【指针】传给函数,那函数的参数该如何设计呢?

下面开始学习!

一维数组传参

传数组名

  • 可以用数组名[]接收,
  • 可以用数组名[个数]接收,指定了具体的
  • 可以用指针接收

 

 二维数组传参

二维数组传参,函数形参的设计只能省略第一个【】数字

因为对于一个二维数组,可以不知有多少行,但是必须知道一行多少个元素

举例子说明如下:

一级指针传参

 

 二级指针传参

1) 

 void test(int **p)

{};

int **p接收一级指针的地址或者二级指针

void test(int **p)

{};
int main()
{
    int *ptr;
    int **pp =&ptr;
    test(&ptr);   //传一级指针的地址
    test(pp);      //传二级指针
    return 0;
}

2)

指针数组传参,int **p接收指针数组

void test(int **p)

{};
int main()
{
    int * arr[10];
    test(arr); //传指针数组
    return 0;
}

函数指针

(数组指针---是指向数组的指针)

函数指针的定义

定义:函数指针---是指向函数的指针,存放函数地址的一个指针

函数指针的是使用

注意:&函数名 和  函数名  都是函数的地址)

用代码演示  &函数名 和  函数名  都是函数的地址

#include<stdio.h>
int Add(int x,int y)
{
    int z=0;
    z=x+y;
    return z;
}
int main()
{
    int a=10;
    int b=20;
    printf("%p\n",&Add);  //取函数的地址
    printf("%p\n",Add);   //函数的地址
}

 运行结果:

使用代码理解函数指针

如何写函数地址的类型呢?int(*p)(int,int)=Add;是关键需要理解的

案例1

#include<stdio.h>
int Add(int x,int y)
{
    int z=0;
    z=x+y;
    return z;
}
int main()
{    
    int a=10;
    int b=20;
    int (*p)(int,int)=Add;   //(*p)说明p是个指针,后面(int,int)说明p后面是函数,
                              //函数类型是int

    printf("%d\n",(*p)(2,3));//调用函数,传实参x=2,y=3
    return 0;
}

分析这行代码:int(*p)(int,int)=Add;

(*p)说明p是个指针,后面(int,int)说明p指向的是个函数,传参内容是int型, 同时函数返回类型是最外面那个int

运行结果

 

 案例2


#include<stdio.h>
void aa(char*str)  //定义一个aa函数,形参是指针类型,返回类型是void
{
	printf("%s\n",str);
}
int main()
{
	void (*p)(char*)=aa;   //aa函数名,代表函数的地址,
	                       //将这个aa函数地址存放到指针p里,用(*p)表示
	                       //然后(*p)后面是(char*)表示指针指向的是函数,是函数类型是char*
	                       //返回类型是void
	                       //这个p就是函数指针

	//调用函数
	(*p)("hell world");

	return 0;
}

运行结果

分析这行代码:void (*p)(char*)=aa;

 //aa是函数名,代表函数的地址,
 //将这个aa函数地址存放到指针p里,用(*p)表示p是个指针
 //然后(*p)后面是(char*),是原括号():表示指针指向的是函数,函数
传参的参数类型是char*
 //返回类型是void
//这个p就是函数指针

(*p)("hello world");

用地址调用函数

今天的任务先到这里结束了,后面接着学习指针进阶!

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值