C语言(第2篇)——指针、数组、函数

目录

1.指针说明

2.函数、数组、指针

3.二维数组

 4.函数指针

5.指针数组

6.指针函数


注意:野指针指没有指明指针内保存的地址。不允许:因为会自由分配一个地址,对其操作很危险。
指针的变与不变:指针变量是变化的,但指针变量指向的地址和值是不变的。

1.指针说明

指针=地址   &取地址  *取值

#include <stdio.h>

int main(viod)
{
	int a=10;
	int *p=&a;   //指针=地址  p为地址变量 &取地址  *取值 
	char *c=&a;  //c为地址变量 
	
	printf("int中a的地址是%p",p);
	printf("\n char中a的地址是%p",c); 
	
	printf("\n int中a的地址是%p",++p);  //自加后不同 
	printf("\n char中a的地址是%p",++c); 	
	return 0; 
} 

作业:输出a,b,c三个数按照顺序输出,函数封装

#include <stdio.h>
void rank(int *a,int *b,int *c);

int main(viod)
{
	int a,b,c;
	int *d,*e,*f;
	
	puts("请输入3个数");
	scanf("%d%d%d",&a,&b,&c);
	rank(&a,&b,&c);
	printf("排序后的三个数为%d,%d,%d",a,b,c);
	return 0; 
} 

void rank(int *a,int *b,int *c)
{
	int tmp;
	int i,j;
	int first,second,third;
	
	if(*a>*b && *a>*c ){
		first=*a;
		if(*b>*c){
			second=*b;
			third=*c;
		}else{
			second=*c;
			third=*b;
		}
	}
	if(*b>*a && *b>*c ){
		first=*b;
		if(*a>*c){
			second=*a;
			third=*c;
		}else{
			second=*c;
			third=*a;
		}
	}	
	if(*c>*b && *c>*a ){
		first=*c;
		if(*a>*b){
			second=*a;
			third=*b;
		}else{
			second=*b;
			third=*a;
		}
	}
	*a=first;
	*b=second;
	*c=third;	
	
}

int a[10]={1,2,3,4,..}

int *p;

p=a; 两个是一样的 p=&a[0];

指针增量和数组的关系

 见怪不怪:

1.指针可以用下标法访问内容。

2.数组用*取内容偏移访问  *a++  //先取a指针中的值再进行地址偏移

2.函数、数组、指针

函数传递传递数组传递的是数组的地址

#include <stdio.h>
void input(int array[],int len);
void output(int array[],int len);
int main(viod)
{
	int array[3];
	int len;
	
	len=sizeof(array)/sizeof(array[0]);
	input(&array[0],len);  //可以是 input(array,len);
	output(&array[0],len);
	return 0; 
} 

void input(int array[],int len)
{
	int i;
	for(i=0;i<len;i++){
		printf("数组的第%d个元素是",i+1);
		scanf("%d",&array[i]);
	}
}

void output(int *a,int len) // 可以是void output(int array[],int len)
{
	int i;
	for(i=0;i<len;i++){
		printf("数组的第%d个元素是%d",i+1,a[i]);  // printf("数组的第%d个元素是%d",i+1,array[i]) 
	} //这里用指针的下标法访问值
}

3.二维数组

二维数组 a[3][4]={{1,2,3,4},{4,5,6,7},{7,8,9,10}}

数组名代表元素的首地址: a为二维数组的首地址= &a[0]     a[0]=&a[0][0]

a位父数组首地址,a[0]为子数组首地址,*a表示子数组首地址(因为a的父数组中存放的都是子数组的地址,取值就是取地址)

a的偏移a+1是  父数组的偏移,a[0]的偏移a[0]+1  是子数组中数的偏移

a[0]+1 表示0行子数组首地址+1 =*(a+0)+1  表示为第0行的第0个元素

第0行的第一个元素的地址表示为a[0][0]

数组只能初始化的时候一起赋值、否则只能单个赋值

#include <stdio.h>

int main(viod)
{
	int a[3][4]={{1,2,3,4},{4,5,6,7},{7,8,9,10}};
	int i,j;
	for(i=0;i<3;i++){
		for(j=0;j<4;j++){
			printf("add:0x%p,值是%d \n",a[i]+j,*(a[i]+j));  %子数组数组名代表元素的首地址
			printf("add:0x%p,值是%d \n",&(a[i][j]),a[i][j]);  %直接取用
			printf("add:0x%p,值是%d \n",*(a+i)+j,*(*(a+i)+j));  %父数组数组名代表元素的首地址
			printf("---------------------------------------\n");
		}
	} 
	return 0; 
} 

4.函数指针

函数指针就是函数名的地址,就是要用指针的方式调用函数。

#include <stdio.h>
int num_plus(int num)
{
	return ++num;	
} 
int main(viod)
{
	int (*p)(int num);  //定义一个函数指针变量  p是变量名 
	
	p=num_plus;  //p指向函数 
	(*p)(10); //函数调用    (*p)相当于取p指针中的值为函数名num_plus 
	printf("调用后的值是%d",(*p)(10));
	return 0; 
} 

练习:使用函数指针,a和b两个数,输入1输出大数,输入2输出小数,输入3输出a+b的和。

#include <stdio.h>
int bigger(int a,int b)
{
	int result;
	
	result=a>b?a:b;
	return result;	
} 

int small(int a,int b)
{
	int result;
	
	result=a<b?a:b;
	return result;	
} 
int sum(int a,int b)
{
	return a+b;	
}  
int handle(int a,int b,int (*p2)(int a,int b))
{
	int result;
	
	result=p2(a,b);
	return result;
}


int main(viod)
{
	int a=10,b=20;
	int cmd;
	int *p;
	int (*p2)(int a,int b);
	int result;
	
	printf("指针的大小是%d",sizeof(p)); 
	printf("函数指针的大小是%d",sizeof(p2));
	
	printf("请输出命令值:\n");
	scanf("%d",&cmd);
	 
	switch(cmd){
		case 1:
			p2=bigger;
			break;
		case 2:
			p2=small;
			break;
		case 3:
			p2=sum;
			break;
		default:
			printf("输入错误。");
			break; 	
	}
	result=handle(a,b,p2);
	printf("结果是%d",result);
	return 0; 
} 

5.数组指针

是指数值的地址

二位数组  array[2][3]={{1,2,3},{7,8,9}};

int (*p)[3]  //定义一个指针,其每次p+1为跳跃一个子数组。

其中p=array,都是指向每次跨越3个值的指针

6.指针数组

int *p[4]  数组里每一个内容是一个指针。

由于[]的优先级比*高,所以p先于[4]结合组成数组,然后p再与*结合,表示数组里存放的是一个指向整数的指针变量。

#include <stdio.h>
int main(void){
	int a=10,b=20,c=30;
	int *p[3]={&a,&b,&c};
	int i;
	
	for(i=0;i<3;i++){
		printf("内容是%d \n",*(p[i]));
	}	
	return 0; 
}

练习:使用函数指针数组,a和b两个数,输入1输出大数,输入2输出小数,输入3输出a+b的和。

#include <stdio.h>
int bigger(int a,int b)
{
	int result;
	
	result=a>b?a:b;
	return result;	
} 

int small(int a,int b)
{
	int result;
	
	result=a<b?a:b;
	return result;	
} 
int sum(int a,int b)
{
	return a+b;	
}  

int main(void)
{
	int a=10,b=20;
	int (*p2[3])(int a,int b)={bigger,small,sum};  //定义了一个函数指针数组  并且初始化 
	int result;
	int i;
	
	for(i=0;i<3;i++){
		printf("result=%d \n",(*p2[i])(a,b));
	}
	return 0; 
} 

7.指针函数

返回值为指针的函数

int *a(int x,int y);   a是函数名。x,y为 函数a的形参,a与()的优先级更高,所以这是一个函数,在函数前面有一个*,表示是函数的返回值是一个指向整型数的指针。

练习:有a个学生b门成绩,要求输出学生序号,打印其所有成绩。

#include <stdio.h>
int *score(int all[][4],int rank){
	int *p;
	p=all[rank];  //p=all+rank
	return p;
}

int main(void)
{
	int rank;
	int all[3][4]={{10,20,30,40},{40,50,60,70},{60,70,80,90}};
	int *p;
	
	printf("请输出要查询学生的序号0 1或2"); 
	scanf("%d",&rank);
	p=score(all,rank) ;
	printf("你查询学生的成绩为%d %d %d %d",*p,*(p+1),*(p+2),*(p+3));

	return 0; 
} 

8.二级(多级)指针

**p可以用于存放指针的指针,能直接访问到数据。*(*p))不行需要**p

#include <stdio.h>

int main(viod)
{
	int data=100;
	int *p=&data;
	
	printf("data的地址是%p存放在p里 \n",p) ;
	printf("data的值是%d存放在p里 \n",*p) ;
	
	//int *p2=&p;   这种定义方式无法访问到data的值 
	//printf("指针p的地址是%p \n",p2) ;   
	//printf("指针p的地址是%p \n",*p2) ;    
	
	int **p2=&p;
	printf("p的地址是%p存放在二级指针p2里 \n",p2) ;
	printf("data的地址是%p存放在一级指针*p2里 \n",*p2) ; 
	printf("data的值是%d存放在**指针p2里 \n",**p2) ;

	return 0; 
} 

9.二级指针与二维数组

二维数组中父数组虽然保存的是指针,但是其不是一个二级指针,不能定义int **p;  p=array;

#include <stdio.h>

int main(viod)
{
	int array[3][4]={{1,2,3,4},{5,6,7,8},{9,2,3,4}};
	int **prr;
	prr=array;
	printf("ppr中存放的地址是:%p \n",prr);
	printf("array的地址是:%p  \n",array);
	printf("array中存放的子数组的地址*prr为:%p \n",*prr);  //所以不能定义为二级指针 
	printf("array中存放的子数组的地址*array为:%p  \n",*array);
	
	int (*p)[4]=array;
	prr=&p;  //这样定义一个二级指针可以 
	//**p=100; 
	printf("array中存放的子数组的地址*prr为:%p \n",*prr);  
	printf("array中存放的子数组的地址*array为:%p  \n",*array);

	return 0; 
} 

10.各种指针的定义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值