C/C++指针之提高篇详解(二)

一、引言

C/C++语言中引入了指针,使得程序能够直接访问内存地址,使得很多复杂的操作变得简单,同时也提高了程序的运行效率。指针即是地址,但是地址却是通过指针变量来存储的。这就好比我们的教室,每个教室都有一个房间号,一个房间号也对应着一间教室,此处的教室就是固定的地址(指针),其地址是通过房间号(指针变量)来表示的。地址就是指针,而房间号就是指针变量。
笔者在《C/C++指针入门详解(一)》一文中给出了指针的基础知识和基本用法。详见链接:
https://blog.csdn.net/sunnyoldman001/article/details/128061186?spm=1001.2014.3001.5502
本文给出了有关指针的更多应用场景及示例,例如函数指针、文件指针、更换数据类型、双指针等等。

二、指针的应用

1.根据需要改变内存中数据的数据类型
例1:在位域中,经常会根据需要把某单一变量存储到内存中,然后根据需要将其转换为结构体类型,进而可以进行一些复杂的操作,例如提取某个或某几个比特位上的数据等。
示例代码:

#include"stdio.h" 
struct weiyu
{
    
    
	unsigned char a:5;
	unsigned char b:2;
	unsigned char c:4;
};
int main()
{
    
    
	weiyu *p;
	unsigned short val = 1521;//10111110001
	//将存储变量a的地址赋值给指针变量p,并将内存中的数据类型改换为结构体 
	p = (struct weiyu*)&val;
	printf("weiyu a = %d\n", p->a);
	printf("weiyu b = %d\n", p->b);
	printf("weiyu c = %d\n", p->c);
	return 0;
}

运行结果:
在这里插入图片描述
说明:
本例中将低比特位0 ~ 4上的“10001”赋值为结构体成员a,因此a的值是17,将比特位5 ~ 6上的“11”赋值为结构体成员b,因此b的值是3,将比特位8 ~ 11上的“101”赋值为结构体成员c,因此c的值是5。比特位7上的“1”被舍弃。
2.文件指针
例2:打开某一文本文本,向屏幕输出该文件内容,并统计字符‘e’出现的次数。
参考代码:

#include "stdio.h"
#include "stdlib.h"
int main()
{
    
    
	FILE *fp;//文件指针
	char ch;
	int count = 0;
	//打开文件,并用文件指针fp指向文件的首地址
	if( ( fp = fopen("file.cpp", "rt" ) ) == NULL )
	{
    
    
		printf("Cannot open file!");
		exit(1);
	}
	ch = fgetc(fp);//从文件中读取一个字符
	while( ch != EOF )
	{
    
    
		putchar(ch);//向屏幕输出读到的字符
		if( ch == 'e' )
		{
    
    
			count++;
		}
		ch = fgetc(fp);
	}
	fclose(fp);//关闭文件
	printf( "\n字母e出现的次数:%d\n", count );
	return 0;
}

运行结果:
在这里插入图片描述
3.双指针
指针可以用来实现函数的双向传值功能,其原理类似于在把指针作为地址(可以看成是一个教室),地址里的内容可以根据需要进行修改(教室里的学生可以更换),以实现双向传值的功能。但是地址本身是不可以更改的(你不能把教室搬家)。但是有些时候还真就是希望可以把地址搬家,那么怎么办呢?其实可以利用双指针来实现,也就是把地址放入新的地址中,类似于在一个教学楼里,在房间号已经固定的情况下,为了满足某一种需要,而重新给教室分配房间号一样,如果把教室看成地址的话,那么教学楼就是一个二级地址,用来存储教室。当把教学楼作为地址单函数参数的话,那么该地址中的内容就可以根据需要随意修改了,这其实就是双指针。
例3:利用函数参数的形式交换两个指针的地址
参考代码:

#include"stdio.h"
#include"malloc.h"
void swap( int **p,int **q ); 
int main()
{
    
    
	int a, b, **p, **q;
	//首先给p和q分配空间,存储的是地址的地址 
	p = (int **)malloc( sizeof(int) );
	q = (int **)malloc( sizeof(int) );
	a = 1;
	b = 2;
	*p = &a;
	*q = &b;
	printf( "交换前地址:p: %x, q: %x\n", *p, *q );
	printf( "交换前的数据:p: %d, q: %d\n", **p, **q );
	swap( p, q );
	printf( "交换后地址:p: %x, q: %x\n", *p, *q );
	printf( "交换后的数据:p: %d, q: %d\n", **p, **q );
	return 0; 
}
//将p和q所指向地址中存储的地址进行交换 
void swap( int **p,int **q )
{
    
      
	int *temp;
	temp = *p;
	*p   = *q;
    *q   = temp;
}

运行结果:
在这里插入图片描述
说明:此用法比较复杂,在双指针被使用前必须要初始化。用时要慎重!!!
4.函数指针
C语言中的函数指针是指向函数的指针变量。用法类似于C++的模板。
定义函数指针的一般形式为:

类型说明符 (*函数名)(形参表) ;

此函数仅仅是一个声明,无函数体。此处的“函数名”严格来说只是一个指针,它指向了某个函数的入口地址。
例4:利用函数指针实现求两个整数的最大值、最小值、和。
参考的代码:

#include"stdio.h" 
int max( int a, int b );
int min( int a, int b );
int sum( int a, int b );
int (*f)(int a, int b);
int main()
{
    
    
	int a = 1, b = 2;
	f = max;
	int c = (*f)( a, b );
	printf( "%2d 和 %2d 的最大值: %2d\n", a, b, c );

	f = min;
	c = (*f)( a, b );
	printf( "%2d 和 %2d 的最小值: %2d\n", a, b, c );
	
	f = sum;
	c = (*f)( a, b );
	printf( "%2d 和 %2d 的和:     %2d\n", a, b, c );
	return 0;
}

int max( int a, int b )
{
    
      
    return a > b ? a : b;  
}
int min( int a, int b )
{
    
      
    return a > b ? b : a;  
}
int sum( int a, int b )
{
    
    
	return a + b;
}

运行结果:
在这里插入图片描述
5.指针数组
指针数组是指数组中的元素都是指针变量,即数组的元素都是地址。常用于字符串数组的操作。
指针数组的定义如下:

类型说明符 *指针变量名[长度];

例5:给定5个字符串,然后统计字符串的最大长度。
参考代码:

#include"stdio.h" 
#include"string.h"
#define N 5
int main()
{
    
    
	int i, length, len;
	char *str[N] = {
    
     "C/C++", "computer", "programming", "pragma", "once" };
	char *maxLenStr;
	length = 0;
	for( i=0; i<N; i++ )
	{
    
    
		if( ( len = strlen( str[i] ) ) > length )
		{
    
    
			length = len;
			maxLenStr = str[i];
		}
	}
	printf( "最长字符串是:%s, 其长度为:%d\n", maxLenStr, length );
	return 0;
}

运行结果:
在这里插入图片描述
说明:在第7行代码,字符串数组中的每个元素均是字符串常量,将其赋值给左端的指针数组,在不同C语言编译器中对其处理的结果是相同的,但是会出现告警信息:将字符串常量赋值为字符指针变量。这是由指针数组中的元素没有进行初始化导致的。

——————————————————————
未完待续!

猜你喜欢

转载自blog.csdn.net/sunnyoldman001/article/details/128079628