C语言指针的应用场景

发布时间 2023-11-18 17:33:09作者: Bonne_chance

C语言指针的应用场景

指针是C语言的精华和灵魂,不懂指针,基本等同于不会C语言。掌握指针,让学会C语言不再成为梦想而成为现实。
指针基本上有三大类:

  • 指向数据的指针
  • 指向函数的指针
  • 泛型指针(void *

指针的应用场景可以分为以下10类:

- 1. 与函数相关的使用
  - 1.1 在函数中用作输出型参数,产生副作用(更新被调用函数中的局部变量的值)
  - 1.2 在函数中用作输出型参数,用于返回多个值
  - 1.3 在函数中用作输入型参数,指向符合类型,避免传值的副作用(性能损耗)
  - 1.4 用作函数返回值,返回一个左值
  - 1.5 用于指向函数的函数指针,使用函数指针调用回调函数
- 2. 用于指向堆内存
- 3. 与`void`配合使用,用`void*`来表示一个泛型指针
- 4. 用于指向数组名(数组指针)
- 5. 用于指向字符串常量(字符串常量指针)
- 6. 在数据结构中,用作链式存储

1. 与函数相关的使用

1.1 在函数中用作输出型参数,产生副作用(更新被调用函数中的局部变量的值)

#include<stdio.h>
void demo(int *arr, int size, int *max){//计算数组最大值
	*max = arr[0];
	for(int i=1;i<size;i++){
		if (arr[i] > *max)
		*max=arr[i];
	}
}

int main(){
	int max, arr[5] = {12, 23, 34, 45, 54};
	demo(arr, 5, &max);
	printf("Max=%d\n",max);
	return 0;
	
}

结果:

1.2 在函数中用作输出型参数,用于返回多个值

#include<stdio.h>
#include<math.h>

int equationSolve(double a, double b, double c,double *x1, double *x2){
	int delta = a*a - 4*a*c;
	if(delta >= 0){
		*x1 = (-b + sqrt(delta))/2*a;
		*x2 = (-b - sqrt(delta))/2*a;
		return 1;
	}
	else
		return 0;
}

int main(void){
	double x1, x2;
	if(equationSolve(1,3,-14,&x1,&x2)){
		printf("x1=%2.f\nx2=%.2f\n", x1,x2);
	}
	else{
		printf("无实根!\n");
	}
	return 0;
}

结果:

1.3 在函数中用作输入型参数,指向复合类型,避免传值的副作用(性能损耗)

#include<stdio.h>

typedef struct Inventory{
	int sku;
	char name[36];
	char unit[12];
	char suppler[48];
	double price;
	double stock;
}Inven;

void demo(const Inven *p){
	printf("The amounts is %f\n",p->price*(*p).stock);
	
}
int main(){
	Inven inven = {123, "carban fibre","kg","uc",128, 100
	};
	demo(&inven);
	return 0;
}

结果:

1.4 用作函数返回值,返回一个左值

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

void printIntArray(void** array, size_t length) { 
    printf("Array at %p\n", array); 
    while (length--) { 
        printf(" [%zu] at %p -> %p", length, array + length, *(array + length)); 
        if (*(array + length)) { 
            printf(" -> %d", *(int*)*(array + length)); 
        } 
        printf("\n"); 
    } 
} 

void* getElement(void** array, size_t index) { 
    return *(array + index); 
} 

int main(int argc, char** argv) { 
    const size_t n = 5; 
    size_t i; 
    
    /* n element array */ 
    void** test = malloc(sizeof(void*) * n); 
    i = n; 
    while (i--) { 
        *(test + i) = NULL; 
    } 
    
    /* Set element [1] */ 
    int testData = 123; 
    printf("testData at %p -> %d\n", &testData, testData); 
    *(test + 1) = (void*)&testData; 
    
    printIntArray(test, n); 
    
    /* Prints 123, as expected */ 
    printf("Array[1] = %d\n", *(int*)getElement(test, 1)); 
    
    getchar();
    return 0; 
} 

该实例报错(需纠正)
1.5 用于指向函数的函数指针,使用函数指针调用回调函数

//通用的冒泡排序函数的应用

#include <iostream>
#include <cstring>
using namespace std;

template <class T>
void sort(T a[], int size, bool (*f)(T,T));
bool increaseInt(int x, int y){return x<y;

}

bool decreaseInt(int x, int y){return x>y;
}

bool increaseString(char *x, char *y){return strcmp(x, y)<0;}
bool decreaseString(char *x, char *y){return strcmp(x, y)>0;}


int main(){
	
	int a[] = {3,1,4,2,5,8,6,7,0,9},i;
	char *b[] = {"aaa", "bbb", "fff", "ttt","hhh", "ddd","ggg","www","rrr","vvv"};
	sort(a, 10, increaseInt);
	for(i = 0;i<10;++i) cout<<a[i]<<"\t";
	cout<<endl;
	sort(b, 10, increaseString);
	for(i=0;i<10;i++) cout<<b[i]<<"\t";
	cout<<endl;
	while(1);
	return 0;
	}


// 通用的冒泡排序函数
template <class T>
void sort(T a[], int size, bool (*f)(T,T))
{
    bool flag;
    int i, j;
    
    for (i = 1; i < size; ++i) {
        flag = false;
        for (j = 0; j <size - i; ++j)	{
            if (f(a[j+1], a[j]))  {
                T tmp = a[j];
                a[j] = a[j+1];
                a[j+1] = tmp;
                flag = true;
            }
        }
        if (!flag) break;	
    }
}

结果:

2. 用于指向堆内存

实质是通过库函数(malloc.h)返回void*指针

#include<stdio.h>
#include<malloc.h>
int** demo(int r, int c){
	int **ap = (int**)malloc(sizeof(int*)*r);
	for(int i=0;i<c;i++){
		ap[i] = (int*)malloc(sizeof(int)*c);
		
	}
	return ap;
}

int main(){
	int r = 3,c = 5;
	int ** ap = demo(r, c);
	int i, j;
	for(i = 0;i<r;i++){
		
		for(j=0;j<c;j++){
				ap[i][j] = (i+1)*(j+1);
		}
		
	}
		
	
	for(i=0;i<r;i++)
	{
		for(j=0;j<c;j++)
			{
			 	printf("%2d ",ap[i][j]);
			}
		printf("\n");
	}
	return 0;
}

结果:

3. 与void配合使用,用void*来表示一个泛型指针

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

int swap2(void *x, void *y, int size){
	void *tmp;
	if((tmp=malloc(size)) == NULL)
		return -1;
	memcpy(tmp,x, size);
	memcpy(x,y,size);
	memcpy(y,tmp,size);
	free(tmp);
	return 0;
	
}

int main(){
	int a = 3, b= 4;
	swap2(&a, &b, sizeof(int));
	printf("%d %d\n",a, b);
	double c = 3, d = 4;
	swap2(&c, &d, sizeof(double));
	printf("%f %f\n", c, d);
	return 0;
	
	
}

结果:

4. 用于指向数组名(数组指针)

#include<stdio.h>
void funcP(int *p, int r, int c){
	for(int i=0;i<r*c;i++)
		printf((i+1)%(r+1) ==0?"%2d\n":"%2d ",*p++);
	printf("\n");	
	
}
void funcAp(int (*p)[4], int r, int c){
	for(int i=0;i<r;i++){
		for(int j=0;j<c;j++)
			printf("%2d ",*(*(p+i)+j));
		printf("\n");
		
	}
	printf("\n");
}

void funcApp(int (*p)[3][4], int r, int c){
	for(int i =0;i<r;i++){
		
		for(int j=0;j<c;j++)
			printf("%2d ",*(*(*p+i)+j));
		printf("\n");
	}
	printf("\n");
}

int main(){
	int arr[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
	int size = sizeof arr /sizeof *arr;
	funcP((int*)arr,3,4);
	funcAp(arr,3,4);
	funcApp(&arr,3,4);
	return 0;
	
	
}

结果:

5. 用于指向一个字符串常量(字符串常量指针)

const char* demo(){
  const char *sp = "hello";
  return sp;
}

关于字符数组和字符指针可以如下图所示:

在字符指针数组,数组元素是一个字符指针,用于指向一个字符串常量,如:

char *pMonth[] = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
char *week[10] = { "Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
char* color[]={"红-red","橙-orange","黄-yellow","绿-green","青-cyan","蓝-blue","紫-purple"};
char *gans[10] = {"甲","乙","丙","丁","戊","己","庚","辛","壬","癸"};
char* zhis[12] = {"子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥"};
char* animals[12] = {"鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪"};

6. 在数据结构中,用作链式存储

#define ElementType int
typedef struct LNode{
  ElementType data;
  struct LNode *next;

}LNode, *LinkList;