C语言指针高级篇

相信很多人都听过指针是c语言的灵魂!

对于指针的学习,往往也是最难的,也是最难搞懂的,那么今天我们一起来学习分析c语言的指针,体会c语言的魅力!
*指针和指针应用大概分为一下几类:
1、字符指针
2、数组指针
3、指针数组
4、数组传参和指针传参
5、函数指针
6、函数指针数组
7、指向函数指针数组的指针
*
*这里我就不列举常见数据类型的指针(如:整形类型的指针int * 双精度类型的指针double 等等), 讲字符指针我会连带说下他们。

字符指针

字符指针它的功能有:
1、指向字符串常量(char str = “abdefg”)
2、指向字符数组(有一个字符数组char str1[20] = {0}; char str = str1;)
3、当字符数组作为实参数传递时,形参采用字符指针接受。

(1)、在这里,我要提一下第1个功能, 当指向字符串常量时,是不能修改字符串里面的值的,因为常量无法修改,你可以访问它,但不可以修改。
(2)、字符串不同于字符,他后面是有结束符’\0’的,千万不能忽略!
*
接下来请大家做一道习题考察下自己的能力吧!

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char str1[20] = "wozhenshuai";
	char *str2 = "wozhenshuai";
	printf("%d, %d\n", sizeof(str1), strlen(str1));
	printf("%d, %d\n", sizeof(str2), strlen(str2));
	system("pause");
	return 0;
}

正确答案是:
20,11
4,11

有没有作对呢?
数组名,他一共有3个含义,1、指向数组首元素的地址,2、sizeof()单目操作符,计算该类型的字节数。当被sizeof()处理时,它默认为指向整个数组,一共20个元素,每个元素都是char类型,char占用一个字节,所以一共为20*1 = 20字节。3、当对数组名取地址符&默认是对整个数组取地址,因此&str1+1 相当横跨整个数组。
字符指针还是很简单的!

数组指针&指针数组

**数组指针和指针数组是比较容易搞混的,区分它们很容易,谁在后面就是什么,所以数组指针是指针,指向的是数组t,
它的形式是char (*pa)[20]
那么同理,指针数组就是数组,数组存放的值是指针!它的形式为char pb[20]
在这里,我强调一下优先级,[]的优先级是该与
的,但是小于()的优先级, 在判断是什么类型的时候,就完全取决于它的优先级排布,
举例:char (pa)[20] ()优先级高于[],我们可以观察到()里面是指针,因此这是一个指针,然后看指针指向什么,
去掉(pa)后剩下char [20],很明显这是一个字符数组, 故这是一个指向字符数组的指针,也就是数组指针。同理指针数组。

**接下来我们来做几道例题,巩固下自己,分析一下是什么类型?指向什么?
(1)、int *p1[6];
(2)、int (*p3)[6];
**
*(1)、第一道题 观察优先级,很明显[]大于,因此这是一个数组,去掉pa[6],剩下int *,因此这是一个存放int *类型的数组,数组里面有6个元素,每个元素都是int *型的
(2)、观察优先级,()大于[],()里面是指针,因此这是一个指针,去掉(*p3),剩下int [6], 因此这是一个指向int [6]数组的指针,(int [6]代表数组整体, 也就是刚才讲的对数组名取地址&)
**

数组传参和指针传参

数组作为实参传递,接受的形参其实是指针,指针传参,则用对应的指针接受。
下面我们做来做几道习题,通过习题来讲解传参问题

#include <stdio.h> 
void print(int *p, int sz) 
{    
	int i = 0;    
	for(i=0; i<sz; i++)   
 	{       
 		printf("%d\n", *(p+i));   
 	 } 
  } 
  int main() 
  {   
    int arr[10] = {1,2,3,4,5,6,7,8,9};   
    int *p = arr;    
    int sz = sizeof(arr)/sizeof(arr[0]);
    print(arr, sz);
    return 0;

仔细观察,整形数组传参过程,不仅传递了数组名(首元素地址),而且还传递sz,这里sz计算的是数组的长度,
为什么呢?这是因为你传递的数组名(也就是数组首元素地址),他是用指针接受的,切忌:指针不等同数组。有相似之处,但是是两个
不同的类型。 才打印函数里面需要数组长度,因此我们需要传递数组长度sz。

#include <stdio.h> 
void test(int** ptr) 
{  
	printf("num = %d\n", **ptr);  
} 
int main() 
{  
	 int n = 10; 
	 int*p = &n; 
	 int **pp = &p;  
	 test(pp);  
	 test(&p); 
	 return 0;
}

这是传递二级指针,没有任何问题,那么接下来看下面一道题!

#include <stdio.h> 
void test(int** ptr) 
{  
	printf("num = %d\n", **ptr);  
} 
int main() 
{  
	int a[3][4] = {0};
	test(a);	
	return 0;
}

*上面的代码对吗? 请各位小伙伴运行下这段代码,看看会出现什么错误。
很明显,实参和形参类型不匹配,二维数组的数据类型不是二级指针,而是数组指针,因此形参写成int (a)[4]

函数指针

函数是由地址的,和指针一样。那么有地址,我们对它进行取地址会出现什么呢? 结果是还是它本身,也就是对函数去地址还是它本身。
如果对函数取地址,我们用什么接收它呢? 对它去取地址会是什么类型呢?
下面看一段程序

void test() 
{  
	printf("hehe\n");
}  
//下面pfun1和pfun2哪个有能力存放test函数的地址? 
void (*pfun1)(); 
void *pfun2();

**这是一个自定义函数test(),我们采用void (pfun1)();来接收它的地址,观察这个函数指针,()里面是指针,这是一个指针类型,指针指向的是一个函数,去掉(pfun),剩下的是void ();。是一个函数,没有形参。 和上面数组指针和指针数组是一样的性质。
那么它有什么用呢?我们可以调用函数,传递函数指针,然后解引用函数指针然后调用函数,使用函数内部的功能。虽说可以直接调用,但是函数指针可以构建成函数指针数组,数组里面都是函数指针,我们调用就像使用数组一样方便。而且更加系统化!

函数指针数组指针&&函数指针数组

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; 
 }

**void (pfunArr[5])(const char str); 首先先找到变量名pfunArr,观察发现它是一个指针数组,去掉pfunArr[5],
剩下void (
)(const char str), 观察发现()里面是,所以它是指针,而且是函数类型的指针,因此这里pfunArr是一个长度为5的数组,
数组里面的元素为函数指针,函数的参数为(const char str),返回值为void。

**

**
void((ppfunArr)[10])(const char),首先先找到ppfunArr,观察发现它是一个指针,去掉ppfunArr,剩下void(* [10])(const char*)
()里面是(* [10]),观察发现它是指针数组,因此它是指向指针数组的指针, 去掉[10], 剩下void ()(const char), 观察发现它是
函数指针, 故这是一个指向指针数组的指针,数组里面存放的是函数指针,函数的参数为const char*,返回值为void。
**

**
函数指针数组和函数指针数组指针是对函数指针更好的调用,更加方便地使用函数功能,他的使用和数组指针和指针数组地使用比较相似,就只是解引用后是函数调用而已!大家多多品味就可以了,很好理解的!
好啦,今天就分享到这里了,最近忙着期末考试,随后空闲时候,我会继续分享和大家共同学习,感受c语言的魅力!
**

发布了25 篇原创文章 · 获赞 16 · 访问量 928

猜你喜欢

转载自blog.csdn.net/weixin_44024891/article/details/94051951