1.1 指针和一维数组
int arr[3];
&arr[0]:数组第一个元素的地址
arr:数组名表示数组的首地址,也就是第一个元素的地址arr = &arr[0]
&arr:表示整个数组的首地址
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[3]={11,22,33};
printf("arr=%p\narr+1=%p\n",arr,arr+1);
printf("&arr[0]=%p\n&arr[0]+1=%p\n",&arr[0],&arr[0]+1);
printf("&arr=%p\n&arr+1=%p\n",&arr,&arr+1);
//arr=&arr[0]
//&arr
int *p=arr;//p=arr
for(int i=0;i<3;i++)
{
// scanf("%d",&arr[i]);
// scanf("%d",arr+i);
// scanf("%d",&p[i]);
// scanf("%d",p+i);
scanf("%d",p++);
//arr++:错误:数组的首地址arr表示常量
}
//地址的等价关系:
//&arr[i]==>arr+i==>&p[i]==>p+i==>p++
p=arr;
for(int i=0;i<3;i++)
{
// printf("%d\t",arr[i]);
// printf("%d\t",*(arr+i));
// printf("%d\t",p[i]);
// printf("%d\t",*(p+i));
printf("%d\t",*p++);
}
//值的等价关系:
//arr[i]==>*(arr+i)==>p[i]==>*(p+i)==>*p++
return 0;
}
练习解读代码:
int a[5]={1,2,3,4,5};
int *p=&a+1;
printf("%d ",*(a+1), *(p-1));
结果:2 5
值的等价关系:
arr[i]==>*(arr+i)==>p[i]==>*(p+i)==>*p++
地址的等价关系:
&arr[i]==>arr+i==>&p[i]==>p+i==p++
1.2 指针和一维字符数组
1> 指针指向一维字符数组的首地址【可以通过指针修改数组的内容】
1.1 使用指针实现字符串的输入输出
char str[] = "hello" ;
char *p = str; //p==str
scanf ("%s",p);
printf ("%s",p);
1.2 指针指向不同的字符数组,地址不同
char str[]="hello";//注意:数组长度在输入时防止越界
char *p=str;//p==str
char str1[]="hello";
char *p1=str1;
printf ("p=%p \n p1=%p \n " ,p ,p1);
*(p+1) = 'K';//可以通过指针改变数组的内容
printf("p=%s\n",p);
2> 指针直接指向字符串常量的首地址【不可以通过指针修改字符串的内容】
char *q="hello";
char *q1="hello";
printf("q=%p q1=%p\n",q,q1);//输出地址一样,指向只读区的字符串常量的首地址 // *(q+1)='Q';//段错误
// printf("q=%s\n",q);
1.3 指针和二维数组
&arr[0][0]:第一行第一列元素的地址
arr[0]:等价于一维数组数组名,列偏移,偏移的是一个元素字节的大小
&arr[0]:等价于一维数组数组名取地址,行偏移,偏移的是一整行字节的大小
arr:行偏移,偏移的是一整行字节的大小
&arr:偏移的是整个数组
练习:使用数组名行列地址转换的输出
//表示2行3列的元素
/* arr :第一行
arr+1: 第二行的行地址
*(arr+1): 表示把第二行的行地址转换为列 arr[1]
*(arr+1)+2:2行3列的地址
*( *(arr+1)+2 ):2行3列的值
*( arr[1] +2 )*/
int arr[2][3];
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
// scanf("%d",&arr[i][j]);
// scanf("%d",*(arr+i)+j); 重点
scanf("%d",arr[i]+j);
不建议
}
}
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
// printf("%d\t",arr[i][j]);
// printf("%d\t",*(*(arr+i)+j));
printf("%d\t",*( arr[i] +j ));
}
printf("\n");
}
地址等价:&arr[i][j] ===> *(arr+i)+j ===> arr[i]+j
值的等价:arr[i][j] ===> *(*(arr+i)+j) ==> *( arr[i] +j )
1.3.1 指针和二维数组结合
#include <stdio.h>
int main(int argc, const char *argv[])
{
int arr[2][3]={11,22,33,44,55,66};
int (*p)[3]=arr; //p=arr
printf("p=%ld\n",sizeof(p));
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
//&arr[i][i] *(arr+i)+j arr[i]+j
// scanf("%d",&p[i][j]);
// scanf("%d",*(p+i)+j);//重要
// scanf("%d",p[i]+j);
scanf("%d",*p+j);//不建议,理解
}
p++;
}
p=arr;
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
// printf("%d\t",p[i][j]);
// printf("%d\t",*(*(p+i)+j));//重要
// printf("%d\t",*(p[i]+j));
printf("%d\t",*(*p+j));//不建议
}
p++;
printf("\n");
}
return 0;
}
练习1:通过数组指针计算二维数组最大值和第二最大值
int main(int argc, const char *argv[])
{
int arr[][3]={66,22,66,44,55,66};
int line=sizeof(arr)/sizeof(arr[0]);//行
int row=sizeof(arr[0])/sizeof(arr[0][0]);//列
int (*p)[3]=arr; //p=arr
printf("p=%ld\n",sizeof(p));
//先最大值,行列下表
int max=**p;
int maxi,maxj;
int second=**p;
for(int i=0;i<line;i++)
{
for(int j=0;j<row;j++)
{
if(max<*(*(p+i)+j))
{
max=*(*(p+i)+j);
maxi=i;
maxj=j;
}
if(second > *(*(p+i)+j))
{
second=*(*(p+i)+j);
}
}
}
//计算第二个最值
for(int i=0;i<line;i++)
{
for(int j=0;j<3;j++)
{
//if(maxi==i && maxj==j)
if(max== *(*(p+i)+j) )
{
continue;
}
if(second <*(*(p+i)+j))
{
second=*(*(p+i)+j);
}
}
}
printf("最大值时:%d 第二大值时:%d\n",max,second);
1.4 数组指针
本质上就是一个指针,主要用来指向二维数组的地址,或者做参数
定义格式:数据类型 (*指针变量名)[常量表达式] ()>[]>*
数据类型:基本数据类型[int float char..],构造数据类型[struct,union,数组]
指针,void
指针变量名:满足命名规范
()[]: 不可以省略
常量表达式:二维数组的列数
int arr[line][row];
int (*p)[row];
1.5 指针数组
本质上是一个数组,表示存储多个指针,满足数组的使用方式
定义格式:数据类型 *数组名[常量表达式] []>*
int *p[3]
数据类型:基本数据类型[int float char..],构造数据类型[struct,union,数组]
指针,void
数组名:满足命名规范
[]: 不可以省略
常量表达式:表示指针的个数
#include <stdio.h>
int main(int argc, const char *argv[])
{
//1>指针数组指向多个变量的地址
int a=11,b=22,c=33,d=44,e=55;
int *p=&a;
int *p1=&b,*p2=&c,*p3=&d,*p4=&e;
int *q[5]={&a,&b,&c,&d,&e};
//q[0]=&a *q[0]
//q[1]=&b
printf("sizeof(q)=%ld\n",sizeof(q));
printf("a=%p b=%p\n",&a,&b);
for(int i=0;i<5;i++)
{
printf("q[%d]=%p\n",i,q[i]);
printf("%d\t",*q[i]);
}
//2>指针数组指向多个数组的地址
int arr1[]={1,2,3};
int arr2[]={4,5,6};
int arr3[]={7,8,9};
int *s[3]={arr1,arr2,arr3};
//s[0]=arr1
for(int i=0;i<3;i++)
{
for(int j=0;j<3;j++)
{
printf("%d\t",*(s[i]+j));
}
}
//3>指针数组指向多个字符串常量的地址
char *m3="hello";
char *m1="word";
char *m2="aaa";
char *m[3]={"hello","word","gsduwyfu"};
for(int i=0;i<3;i++)
{
printf("%s\n",m[i]);
}
1.6 多级指针
一级指针:存储普通变量的地址
二级指针:存储一级指针的地址
三级指针:二级指针的地址
.....
定义格式: 数据类型 **指针变量名
注意:*的个数不限
#include <stdio.h>
int main(int argc, const char *argv[])
{
int a=11;
int *p=&a;
int **q=&p;
int ***s=&q;
printf("***s=%d\n**q=%d\n*p=%d\n",***s,**q,*p);
printf("p=%p\n*q=%p\n**s=%p\n",p,*q,**s);
return 0;
}
1.7 void和指针
定义格式: void *指针变量名
通用类型指针,它可以指针任何一种类型的地址,可以指向任何一块空间,但是
在使用时,必须要进行强制转换。
int a=11;
float b=1.1;
char c='a';
void *p=&a;
printf("p=%p *p=%d\n",p,*(int *)p);
p=&b;
printf("p=%p *p=%f\n",p,*(float *)p);
p=&c;
printf("p=%p *p=%f\n",p,*(char *)p);
1.8 const和指针
1> const修饰的变量不可以改变值
2> const修改的全局变量在.ro段
3> const修改的局部变量在栈区
4> const和指针
const int *p: *在const的右边,const修饰的是值,值不可以改变,地址可以改变
int const *p:*在const的右边,const修饰的是值,值不可以改变,地址可以改变
int * const p:*在const的左边,const修改的是地址,值可以改变,地址不可以改变
const int * const p:const修改的是地址和值,值不可以改变,地址不可以改变
#include <stdio.h>
int main(int argc, const char *argv[])
{
1> 认识argc和argv
//argc:命令行输入参数的个数
//argv:指针数组,接收命令行输入的字符串
printf("argc=%d",argc);
for(int i=0;i<4;i++)
{
printf("%s\t",argv[i]);
}
#if 0
//const int a=10;
//a=100;
2>const int *p: *在const的右边,const修饰的是值,值不可以改变,地址可以改变
int a=10;
int b=100;
const int *p=&a;
// *p=100;//改变值
p=&b;
printf("*p=%d\n",*p);
3>int const *p:*在const的右边,const修饰的是值,值不可以改变,地址可以改变
int const *p1=&a;
// *p1=b;//改变值:报只读的错误
p1=&b;
printf("*p1=%d\n",*p1);
4>int * const p:*在const的左边,const修改的是地址,值可以改变,地址不可以改变
int *const p2=&a;
*p2=9999;
// p2=&b;改变地址:报只读的错误
printf("*p2=%d\n",*p2);
5>const int * const p:const修改的是地址和值,值不可以改变,地址不可以改变
const int * const p3=&a;
// *p3=b;
p3=&b;
printf("*p3=%d\n",*p3);
#endif
return 0;
}
作业:
练习1:使用指针实现两个字符串的比较【非函数实现】
练习2:使用指针实现字符串连接【非函数实现】
练习3:使用指针实现字符串逆置【纯指针】
char *p=str;
p
char *q=str+strlen(str)-1
abcde
0x10
i j
练习4:通过数组指针二维数组实现杨慧三角
if(j==0 || i==j)
{
arr[i][j]=1;
*(*(p+i)+j)=1;
}
else
{
arr[i][j]=arr[i][j-1]+arr[i-1][j-1]
*(*(p+i)+j-1)
}
练习5:通过数组指针实现二维数组转置[选做]
int arr[2][3]={1,2,3,4,5,6}
1 2 3
4 5 6
int brr[3][2]
1 4
2 5
3 6
brr[0][0]=arr[0][0]
brr[1][0]=arr[0][1]
brr[2][0]=arr[0][2]
brr[j][i]=arr[i][j]