《C语言程序设计》指针

Posted 杰西啊杰西

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《C语言程序设计》指针相关的知识,希望对你有一定的参考价值。

记录学习过程中的知识点

文章目录

一、指针引用数组

1.1 数组与指针

数组名a代表数组首元素的地址,是一个指针型常量,其值在程序运行期间固定不变

1.2 多维数组与指针

1.2.1 多维数组元素的地址

1.2.2 指向多维数组元素的指针变量

1、指向数组元素的指针变量

也就是把而为二维数组扯开,看做一个一维数组,计算目标元素的相对位置

a[i][j]的相对位移: i*m + j

2、指向由m个元素组成的一维数组的指针变量

int (*p)[4]; 指针变量p的基类型为包含4个元素的一维数组,长度为16字节
printf("%d",*(*(p+i)+j));  输出a[i][j]的值

3、指向数组的指针作为函数参数

float score[3][4]=65,50,66,70,80,56,99,100,56,77,55,36;
average(*score,12); // 求12个分数的总平均数
search(score,2);  //求序号为2的学生的成绩
void average(float *p,int n)

    float *p_end;
    float sum=0,aver;
    p_end=p+n-1;
    for(;p<=p_end;p++)
   		sum=sum+(*p);
   	aver=sum/n;
   	printf("%d",aver);

void search(float(*p)[4],int n)

    int i;
    for(i=0;i<4;i++)
    	printf("%5.2f",*(*(p+n)+i));

二、指针引用字符串

2.1 引用字符串的两种方式

2.1.1 字符数组

使用字符数组存放一个字符串,通过数组名否则下标引用字符串中的一个字符,也可以通过数组名和格式申明“%s”输出该字符串。

char string[]="I love China!";
printf("%s\\n",string);
printf("%c\\n",string[3]);

字符数组初始化时,长度是确定的,长度因为14,其中13个字节存放“I love China!”,第14个字节存放 ‘\\0’

'\\0’的ASCII码为0

2.1.2 字符指针变量

使用字符指针变量指向一个字符串常量并应用

char *string = "I love China";
printf("%s",string);

等价于

char *string;
string = "I love China!";

C语言只有字符变量,没有字符串变量

2.2 对字符串中字符的存取

2.2.1 下标法

char a[]="I am a student", b[20];
for(int i=0;*(a+i)!='\\0',i++)
	*(b+i)=*(a+i);
*(b+i)='\\0';

2.2.2 指针变量法

char a[]="I am a student", b[20],*p1,*p2;
p1=a;
p2=b;
for(;*p1!='\\0';p1++,p2++)
	*p2=*p1;
*p2='\\0';

2.3 字符指针做函数参数

char a[]="I am a teacher";
char b[]="I am a student";
void copy_string(char from[],char to[])

2.3.1 字符数组名做函数参数

copy_string(a,b);

2.3.2 字符型指针变量做实参

char *from=a,*to=b;
copy_string(from,to);

2.3.3 字符型指针变量做形参和实参

void copy_string(char *from,char *to)

tips
字符数组中各元素的值是可以被改变的,可以再对它们进行赋值
字符指针变量指向的字符串常量中的内容是不可以被取代的,不可以再对其赋值

正确:

char str[]="I love China";
a[2]='*';

错误:

char *b="I love China";
b[2]='*';

三、指向函数的指针

3.1 函数与指针

函数名代表函数的起始位置

指向函数的指针变量——存放某一函数的起始地址

int (*p)(int,int);

p是一个指向函数的指针变量,它可以指向函数类型为整型且只有两个整型参数的函数

3.2 指针变量调用函数

int a=1,b=2,c;
int (*p)(int,int);
p=max;
c=(*p)(a,b);
printf("%d",c);
int max(int x,int y)

	return z=x>y?x:y;

此时 指向函数的指针p 和 函数名max 同时指向函数的起始地址

tips:

  • 再给函数指针变量赋值时,只需给出函数名不必给出参数
  • 用函数指针变量调用函数时,只需将(*p)代替函数名即可
  • 对指向函数的指针变量不能进行算数运算

3.3 指向函数的指针作函数参数

指向函数的指针变量的一个重要用途就是把函数的入口作为参数传递到其他函数

void fun(int (*x1)(int),int(*x2)(int,int)) // f1,f2

	int a,b,i=3,j=5;
	a=(*x1)(i);		//调用f1函数,i是实参
	b=(*x2)(i,j);	//调用f2函数,i,j是实参

应用案例:

int fun(int x,int y,int(*p)(int,int));
int max(int,int);
int min(int.int);
int i;
scanf("%d",&i);
if(n==1) printf("max:%d\\n",fun(a,b,max));
else printf("min:%d\\n",fun(a,b,min));
int fun(int x,int y,int(*p)(int,int))

	return (*p)(x,y);

还可求定积分的通用函数

四、返回值指针值的函数

案例:输出第k个学生的所有成绩

float *search(float(* pointer)[4],int n)

	float *pt;
	pt=*(pointer+n);
	return pt;

void main()

	float score[3][4]=65,50,66,70,80,56,99,100,56,77,55,36;
	float p;
	int k;
	scanf("%d",&k);
	p=search(score,k);
	for(int i=0;i<4;i++)
		printf("%5.2f\\t",p+i);
	printf("\\n");

案例:输出所有不及格学生4门课程的成绩

float *search(float(*pointer)[4])

	float *pt;
	pt=NULL;
	for(int i=0;i<4;i++)
		if(*(*pointer+i)<60)
			pt=*pointer;
	return pt;

int main()

	float score[3][4]=65,50,66,70,80,56,99,100,56,77,55,36;
	float *p;
	for(int i=0;i<3;i++)
	
		p=search(score);
		if(p)
		
			for(int j=0;j<4;j++)
				printf("%5.2f\\t",*(p+j));
		
		printf("\\n");
	
	return 0;

五、指针数组

一个数组,其元素均为指针类型数据
指针数组中的每一个元素都存放一个地址,相当于一个指针变量

int *p[4];

5.1 案例

案例:将若干字符串按照字母顺序排序

选择法排序:

void sort(char *name[],int n)

	char *temp;
	for(int i=0;i<n-1;i++)
	
		for(int j=i+1;j<n;j++)
			if(strcmp(name[k],name[j])>0)
				k=j;
		if(k!=i)  //指向互换
		
			temp=name[i];
			name[i]=name[k];
			name[k]=temp;
		
	

int main()

	char *name[]="Hello Jack","BASIC","Great Wall","Java","Computer Sience";
	int n=5;
	sort(name,n);
	for(int i=0;i<n;i++)
		printf("%s\\n",name[i]);
	return 0;

5.2 指针数组做main函数形参

int main(int argc, char *argv[])
  • argc:int型变量,表示接受形参的个数
  • argv[]:字符指针数组,用来接收从操作系统命令行中传来的字符串中首字符的地址

假设命令行中输入:
// 程序文件名为file1.exe
// 命令行中的参数都是字符串

file1 China Beijing

则向main函数中传入的参数个数为3,参数分别为file1,China,Beijng
但是我们在写程序处理时,一般没有用文件名,所以要注意跳过第一个参数(文件名file1)

六、多重指针(指向指针数据的指针)

char **p;

char *(*p)  // 表示p指向的是char*型的数据,p指向一个字符指针变量

如果引用*p,就得到p所指向的字符指针变量的值

char *name[]="Hello Jack","BASIC","Great Wall","Java","Computer Sience";
char **p;
for(i=0;i<5;i++)

	p=name+i;
	printf("%s\\n",*p);

return 0;

七、动态内存分配与指向它指针变量

7.1 内存的动态内存分配

全局变量分配在诶村长的静态存储区
局部变量分配在内存中的动态存储区——栈

内存动态分配区域——堆
用于存放一些临时用的数据,需要时随时开辟,不需要时随时释放,根据需要向系统申请所需大小的空间,由于未在声明部分定义其类型,所以只能通过指针进行引用

7.2 建立内存的动态分配

#include <stdlib.h>

7.2.1 malloc()

  1. 函数原型
void *malloc(unsigned int size)
  1. 作用:
  • 在内存的动态存储区分配一个长度为size的连续空间,
  • 返回值是所分配区域的第一个字节的地址,
  • 指针基类型为void(不指向任何类型的数据,只是提供一个纯地址),如果内存空间不足,返回空指针NULL
  1. 使用
malloc(100);

7.2.2 calloc()

  1. 函数原型
void *calloc(unsiged n,unsigned size)
  1. 作用:
  • 在内存的动态存储区中分配n个长度为size的连续空间
  • 动态数组
  1. 使用
calloc(50,4); // 开辟50x4个字节的临时分配域,把首地址赋给指针变量p

7.2.3 realloc()

  1. 函数原型
void *realloc(void *p,unsigned int size)
  1. 作用
  • 使用realloc函数重新分配通过malloc或者calloc函数获得的动态空间大小
  1. 使用
realloc(p,50);

7.2.4 free()

  1. 函数原型
void free(void *p);
  1. 作用
  • 释放指针变量p所指向的动态空间,使这部分空间能够重新被其他变量使用
  1. 使用
free(p);

7.2.5 void型指针变量

void型指针变量——指向空类型不指向确定的类型,再将它的值赋给另一指针变量时,由系统对它进行类型转换,是指适合与被复制的变量的类型

地址应该包含基类型的信息,这样就知道存储单元大小,实现对数据的存取,这种无指向的地址所标志的存储单元中是不能储存任何数据的,故无法通过这种地址对内存存取数据,

在程序中它只是过渡性的,只有转化为有指向的地址,才能存取数据。

int *p;
p = (int *)malloc(5*sizeof(int)); //调用malloc返回的是void*型的,要将其赋给p,必须要进行类型转换

八、指针小结

  1. 地址,按照指针型数据的存储方式存储
  2. 一个地址型的数据包含
  • 表示内存编号的纯地址
  • 指针类型
  • 以它为标识的存储单元存放的数据类型——基类型
  1. 指针就是地址,指针变量用来存放地址
  2. 指针变量归纳比较
  3. NULL 可以使p指向地址为0的单元
#define NULL 0
p=NULL;

以上是关于《C语言程序设计》指针的主要内容,如果未能解决你的问题,请参考以下文章

浅谈C语言的动态内存开辟

C语言学习笔记(16)动态内存管理

C语言——指针(进阶)

C++中new的用法

C语言堆内存管理上出现的问题,内存泄露,野指针使用,非法释放指针

刨析《C语言》进阶付费知识完结