目录
注意:野指针指没有指明指针内保存的地址。不允许:因为会自由分配一个地址,对其操作很危险。
指针的变与不变:指针变量是变化的,但指针变量指向的地址和值是不变的。
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;
}