指针引入:
开胃小菜:
定义一个变量,然后将其输出(新内容指针引入)
// 指针 == 地址,地址就是指针,指针就是地址。
// 变量包含四种概念:int(类型) a(变量名) (内存地址)= 10(值)
#include <stdio.h>
// 什么是整型变量,存放整型数的变量
// 什么是字符变量,存放字符的变量
// 什么是指针变量,存放指针的变量
// 什么是指针变量,存放地址的变量
int main()
{
int a = 10 ;
int *b; //这里的*是一个标识符,告诉系统我是一个指针变量,是用来保存别人地址的变量,不是取值运算,
b = &a;
printf("a = %d \n",a);
printf("a的地址是: %p \n",&a);
printf("a的地址是: %p \n",b); // 通过指针访问地址
printf("a地址访问: %d \n",*(&a)); // *取值运算符,他把后面跟的内存地址中的数据“取出来”。
printf("指针变量的访问方式 %d \n",*b); //通过指针取值
return 0 ;
}
由此可见,指针 = 地址 地址= 指针
指针变量和其他类型的变量一样,也有四要素:
变量名、类型、(存储空间)地址、值
有关指针变量注意事项:
① 定义指针变量要区分其类型;(详情可看代码注释)
② 定义指针变量时标识符*的应用(标识符只产生在指针变量定义或申明的时候,与运算符不同);
③ 取地址符号&;
④ 打印指针变量时取值运算符*的应用;
⑤ 指针变量作为一个变量,也有它自己的地址;
指针类型:
代码验证:
#include <stdio.h>
//指针类型:
int main()
{
int a = 0x1234;// 以十六进制的方式 int 4个字节 char 1个字节 一个字节等于8位
int *b = &a;
char *c = &a;
// 打印b、c 的地址。 地址一样
printf("b = %p \n",b);
printf("c = %p \n",c);
// 以十六进制方式打印 b、c。
printf("a = %x\n",*b); //这里输出是全部输出,因为a是int 的类型, int是4个字节 一个字节8位 32 可以全部访问完毕
printf("a = %x\n",*c); // 这里输出只能输出34,因为char是一个字节, 一个字节8位 8位只能访问34.
/*取值运算符会根据指针变量类型,访问不同大小的存储空间。
区分指针变量类型不仅能够决定指向空间的大小,而且还能决定增量。*/
printf("a的地址加1是:%p\n",b+1); // 地址自增
printf("a的地址加1是:%p\n",c+1);
return 0 ;
}
取值运算符会根据指针变量类型,访问不同大小的存储空间。区分指针变量类型不仅能够决定指向空间的大小,而且还能决定增量。
指针作用:
编程练习:封装一个函数,实现两个数的交换
当使用函数调用的时候,形参里面的变量是临时地址,在形参里不管如何操作,其结果不会传到main函数中,因为不是同一个地址。
/*#include <stdio.h>
// 输入2个数a,b,; 要求不管怎么输入,在输出的时候,a,b就是由大到小的顺序输出,用函数封装实现
void inArry(int a,int b)
{
int tmp;
tmp = a;
a = b;
b = tmp;
}
// 这里的变量名 与main函数的变量名不是同一个地址,
// inArry中的变量名地址是临时地址。
int main()
{
int a,b;
printf("请输入两数\n");
scanf("%d%d",&a,&b);
printf("a= %d\n",a);
printf("a= %d\n",b);
inArry(a,b);
printf("交换之后的a = %d,d = %d\n",a,b);
return 0;
}*/
#include <stdio.h>
//把*pdata1(指针) 当成一个变量去看
void ChangeData(int *pdata1,int *pdata2,int *pdata3)
{
int temp;
if(*pdata1 < *pdata2){
temp = *pdata1;
*pdata1 = *pdata2;
*pdata2 = temp;
}
if(*pdata1 < *pdata3){
temp = *pdata1;
*pdata1 = *pdata3;
*pdata3 = temp;
}
if (*pdata2 < *pdata3){
temp = *pdata2;
*pdata2 = *pdata3;
*pdata3 = temp;
}
}
// 通过指针传的相同地址,所以会交换成功。
int main()
{
int data1 ,data2,data3;
puts("原样输入");
scanf("%d%d%d",&data1,&data2,&data3);
printf("data1 = %d data2 = %d data2 = %d\n",data1,data2,data3);
ChangeData(&data1,&data2,&data3); //传地址。
puts("排序后输出");
printf("data1 = %d data2 = %d data3 = %d\n",data1,data2,data3);
return 0;
}
指针变量_通过指针指向数组: int *p
定义了一个指针变量:
int *p ;指针变量
对p 取值 就是 通过指针,对第0个元素的地址等于p
什么是指针变量 -就是保存地址的变量。
int a【10】;
p = & a【0】 // 下标法,第0个元素的地址等于p
编程练习:
#include <stdio.h>
// 指针_变量
int main()
{
int arry[10]= {1,5,7,8,9,11,25,14,16,24};
int *p ;
p = &arry[0]; //p的值是a[0]的地址;数组的首地址就是首个元素的地址
// p 的值是数组a的名称 就是数组的首地址
p = arry ;
printf("第0个元素是:%d\n" ,*p); //打印值
printf("第0个地址是:%p\n" ,p); // 打印地址
// 指针地址延申(偏移)
printf("第1个元素是:%d\n" ,*(p+1)); // 地址向后延申4个字节 5
printf("第2个元素是:%d\n" ,*(p+2)); // 地址向后延申8个字节 7
printf("done\n");
// 通过for循环进行 向后延申
int i ;
for(i = 0 ;i<3;i++){
// printf("第%d个元素是:%d\n" ,i,*(p+i));
//printf("第%d个元素是:%d\n" ,i,*p++); //先*p,在++。
printf("第%d个元素是:%d\n" ,i,*p); //先*p,在++。
p++;
}
//注意 有一个问题,同样的代码再来一次,就会出现地址错误,
p = arry ;
// 将指针地址重新回到首元素。就可以解决地址错误。
//数组初始化!!!当使用指针偏移来访问数组时,要注意指针是否越界
for(i = 0 ;i<3;i++){
// printf("第%d个元素是:%d\n" ,i,*(p+i));
//printf("第%d个元素是:%d\n" ,i,*p++); //先*p,在++。
printf("第%d个元素是:%d\n" ,i,*p); //先*p,在++。
p++;
}
return 0;
}
见怪不怪 :指针下标法
#include <stdio.h>
// 指针地址见怪不怪 面试题
int main()
{
int arr[3] = {1,0,3};
int *p ; // *p 是指针变量, arr数组是常变量
p = arr; // == p = &arr[0] 下标法
// 指针通过下标法,访问指定的数组元素,如p[2]
printf("数组第3位的元素是:%d\n",p[2]);
for(int i = 0;i <3;i++){
printf("数组第%d的元素是:%d\n",i,p[i]); // 通过下标法,访问指定的数组元素。
}
return 0;
}
见怪不怪 :数组名
#include <stdio.h>
// 指针地址见怪不怪 面试题
int main()
{
int arr[3] = {1,0,3};
int *p ; // *p 是指针变量, arr数组是常变量
p = arr; // == p = &arr[0] 下标法
// 数组名通过下标法,访问指定的数组元素,如arr[2]
printf("数组第3位的元素是:%d\n",arr[2]);
for(int i = 0;i <3;i++){
printf("数组第%d的元素是:%d\n",i,arr[i]); // 通过下标法,访问指定的数组元素。
}
return 0;
}
见怪不怪 :指针
#include <stdio.h>
// 指针地址见怪不怪 面试题
int main()
{
int arr[3] = {1,0,3};
int *p ; // *p 是指针变量, arr数组是常变量
p = arr; // == p = &arr[0] 下标法
// 数组名通过下标法,访问指定的数组元素,如arr[2]
printf("数组第3位的元素是:%d\n",*(p+3));
for(int i = 0;i <3;i++){
printf("数组第%d的元素是:%d\n",i,*(p+i)); // 通过下标法,访问指定的数组元素。
}
return 0;
}
数组名++??
arr++ 数组名指针常量 是不可以的++的 指针地址++ 可以
*p 是保存地址的变量 ,你可以的变量进行操作,不能对指针常量操作。
printf("数组第%d的元素是:%d\n",i,*p++); // 先取地址 在加加。
#include <stdio.h>
// 指针地址见怪不怪 面试题
int main()
{
int arr[3] = {1,0,3};
int *p ; // *p 是指针变量, arr数组是常变量
p = arr; // == p = &arr[0] 下标法
for(int i = 0;i <3;i++){ //arr++ 数组名指针常量 是不可以的 指针地址++ 可以
// *p 是保存地址的变量 ,你可以的变量进行操作,不能对指针常量操作。
printf("数组第%d的元素是:%d\n",i,*p++); // 先取地址 在加加。
}
return 0;
}
sizeof地址大小不一样
#include <stdio.h>
// 指针地址见怪不怪 面试题
int main()
{
int arr[3] = {1,0,3};
int *p ; // *p 是指针变量, arr数组是常变量
p = arr; // == p = &arr[0] 下标法
// sizeof(数组名) 表示整个数组用多少个字节, sizeof(指针变量)表示首个地址,在计算机内存当中首地址用多少个字节。
printf("sizeof arr is %d \n",sizeof(arr)); // 12 arr 数组名 12个字节 一个字节 4位。 计算整个数组的大小
printf("sizeof arr is %d \n",sizeof(p)); //8 指针首个地址 占8个字节 在本操作系统指针存放一个地址所用的8个字节。
printf("sizeof arr is %d \n",sizeof(int)); //4 整型数 占4个字节
printf("sizeof arr is %d \n",sizeof(int*)); //8 int指针 本操作系统存放一个地址所用的8个字节
printf("sizeof arr is %d \n",sizeof(char*)); //8 char 指针 本操作系统存放一个地址所用的8个字节
return 0;
}
指针和二维数组:
二维数组:父子数组
父数组 = a 行地址 a 是数组的名字,也是二维数组第0行的首地址。
a = a+0 表示在第0行
a+1 表示在第1行
子数组 = a[0] ,*a列地址 a[0]表示在第0列 也是第0列的首地址,
a[0]+0 表示第o行第0列
a[0]+1 表示第o行第1列
此处的a[0],a[1],a[2]中的0,1,2并不代表数组的大小,而代表数组的名字。
数组名就是数组的首地址(列地址),因此数组的首地址就是首个元素的地址,
思考:a是谁的地址,a[0]又是什么,那*a或者*(a+0)呢?
a是数组名 即父数组(行)首地址;
a[0]是子数组(列)首地址;
*a = *(a+1)=a[0]子数组(列)首地址;
原因是:*a相当于是取数组a里面的值,而二维数组里还有一维数组,c语言里没有直接操作数组的概念,操作的是数组首地址,操作的实际上是列地址。所以*a = a[0]
*(a+0)== a[0]
原因是:括号的优先级要高于取值符号(星号),所以先执行括号里的,即*(a+0) = *a = a[0])
即:a[0] (数组名)= *(a+0)(指针)= &a[0][0](下标);
a[0]+1(数组名) = &a[0][1](下标法)= *(a+1)(指针)
a[0]+1:是第0行第一列的地址,是地址的意思(相当于*(a+0)+1),也可以说是第0个子数组的第1个元素的地址,而第0个子数组的第1个元素表示方式是a[0][1]。
#include <stdio.h>
int main()
{
int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,100,12,18}};
printf("a的父地址是:%p,偏移1后的地址是:%p\n",a,a+1);
printf("数组名:a[0]的子地址是:%p,偏移1后的地址是:%p\n",a[0],a[0]+1);
printf("指针法:a[0]的子地址是:%p,偏移1后的地址是:%p\n",*(a+0),*(a+0)+1);
printf("指针法取值:a[0]的子数值是:%d,偏移1后的地址是:%d\n",*(*(a+0)),*(*(a+0)+1));
//* a =a[0] ,*a+1=a[0][1];
return 0;
}
补充知识点:
基础:
进阶:
思考:
虽然a+1和*(a+1)的地址和值是相同,但它们所代表的意义不一样。
a+1是面向行的地址(父数组),*(a+1)代表的是面向列的地址(子数组)。
面试题:
代码展示:
#include <stdio.h>
// 二维指针数组
int main()
{
int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,100,12,18}};
int i,j;
for(i=0;i<2;i++)
{
for(j=0;j<3;j++)
{
printf("address1: %p,value: %d\n",&a[i][j],a[i][j]); // 下标法访问。
// a[i]+j 这是一个地址 对地址取值 加*
printf("address2: %p,value: %d\n",a[i]+j,*(a[i]+j));
//虽然a+1和*(a+1)的地址相同,值相同,但它们所代表的意义不一样,a+1是面向行的地址,*(a+1)代表的是面向列的地址。
// (a+i)+j != a[i]+j ;*(a+i)+j )=a[i]+j
printf("address3: %p,value: %d\n",*(a+i)+j,*(*(a+i)+j)); //
printf("=======================================\n");
}
}
return 0;
}
数组指针: int (*p)[4]
编程练习: 指向一个含有4个元素的数组
#include <stdio.h>
// 二维指针数组
int main()
{
int a[3][4] = {{11,22,33,44},{55,66,77,88},{99,100,12,18}}
int i,j;
int *p; // 子数组
//p = &a[0][0]; // 下标 0行0列首地址 == p
//p=arr;
// 数组指针 定义一个指针,指向数组
//数组指针 才是真正等同于二维数组名
int (*p2)[4]; // 定义指向子数组的指针
p2 = a; // 指向父数组的指针
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
printf(" %p\n",*(p2+i)+j); //打印12元素的地址。
printf(" %d\n",*(*(p2+i)+j)); // 打印元素的值
}
}
printf("p2=%p,\n",p2);// 打印父数组的地址
// 先自增,在取值
printf("p2=%p\n", ++p2); // 打印自增后的父数组地址
return 0;
}
编程练习:输出二维数组任意行列的数
#include <stdio.h>
void inArry(int *hang, int *lie ){
printf("请输入行和列的值\n");
scanf("%d%d",hang,lie);
puts("doen!");
}
int petArry(int hang,int lie,int (*p)[4]){
int data;
data = *(*(p+hang) +lie);
return data ;
}
int main()
{
int hang, lie;
int arry[][4]={
{33,55,24,67},
{66,88,98,77},
{65,28,57,46},
{18,26,57,44}};
int *p;
inArry(&hang,&lie);
int over = petArry(hang,lie,arry);
printf("第%d行,第%d列的数值是%d\n",hang+1,lie+1,over);
return 0;
}
函数指针: int (*p)(int a , int b)
定义:如果在程序中定义了一个函数,在编译时,编译系统为函数分配一段存储空间,这段存储空间的起始地址(又称入口地址)称为这个函数的指针。
函数名就是地址,访问的时候能用函数名访问,也能通过函数指针访问(和数组指针一样)
优点:根据程序运行过程的不同情况,调用不同的函数。
如何定义一个函数指针变量:将函数整体复制下来,然后把函数名定义成指针变量。
例如:
定义有参数,有返回值类型的函数指针:int data(int a,int b);定义函数指针为int (*p)(int a,int b)后p = data;调用的时候直接调用(*p)(int a,int b);
int data(int a,int b);
p = data()
data(int a,int b); 正常函数调用法
(*p)(int a,int b); 函数指针调用法
定义无参数无返回值类型的函数指针:void data(int a,int b)定义函数指针为void (*p)()后p = data;调用的时候直接调用(*p)();
void data(int a,int b)
p = data()
data(int a,int b); 正常函数调用法
(*p)(int a,int b); 函数指针调用法
代码验证:
#include <stdio.h>
//函数地址(指针)
void print()
{
puts("程序启动\n");
}
int includ(int data){
data ++;
return data ;
}
int main()
{
print(); //普通函数调用
void (*p)(); // 定义一个指针函数变量(函数指针变量)
p = print; // 指向函数
(*p)(); // 指针函数调用 调用函数print (*p)指针
int a = 10; //定义了一个整型 变量 变量名为a,值为10;
int *pa; //变量指针 对pa的地址取值
pa = &a; // 将a的地址赋值给pa
printf("变量a = %d\n",*pa);
int data =20; //定义了一个整型 变量 变量名为data,值为20;
int (*d)(int data); // 定义了一个函数指针,并对函数调用传了个形参。
d = includ; // 函数 赋值给了d
int over =(*d)(data); // 调用函数includ,并传参
printf("测试:%d",over);
return 0;
}
编程练习:
例8.24 有两个整数a和b,由用户输人1,2或3.如输人1,程序就给出a和b中大者,输人2,就给出a和b中小者,输人3,则求a与b之和。
#include <stdio.h>
//函数地址
int a = 20;
int b = 45;
int inarr(int a ,int b){
return a > b ?a :b ;
}
int petarr(int a ,int b){
return a < b ?a :b ;
}
int getarr(int a ,int b){
return a + b ;
}
int main(){
int i ;
printf("请输入一个值\n");
scanf("%d",&i);
if(i==1){
int (*big)(int a,int b);
big = inarr;
(*big)(a,b);
printf("两者之间的大数是%d",(*big)(a,b)) ;
}
if(i==2){
int (*loat)(int a,int b);
loat = petarr;
(*loat)(a,b);
printf("两者之间的小数是%d",(*loat)( a,b));
}
if(i==3){
int (*sum)(int a,int b);
sum = getarr;
(*sum)(a,b);
printf("两者之间的和数是%d",(*sum)( a,b));
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int GetMaxData(int data1,int data2)
{
return data1>data2?data1:data2;
}
int GetMinData(int data1,int data2)
{
return data1<data2?data1:data2;
}
int GetSumData(int data1,int data2)
{
return data1+data2;
}
int GetSubData(int data1,int data2)
{
return data1-data2;
}
// 定义函数:根据传入的函数指针计算最终结果
int GetlastData(int data1,int data2,int (*p)(int data1,int data2))
{
int data;
data = (*p)(data1,data2);
return data;
}
int main()
{
int data1 = 20;
int data2 = 10;
int cmd;
int result;
int (*p)(int data1,int data2); // 定义了一个指向函数的指针变量。
printf("Please Enter the number:1(max),2(min),3(sum),4(sub)\n");
scanf("%d",&cmd);
switch(cmd)
{
case 1:
p = GetMaxData;
break;
case 2:
p = GetMinData;
break;
case 3:
p = GetSumData;
break;
case 4:
p = GetSubData;
break;
default:
printf("输入错误,请重新输入\n");
exit(-1);
break;
}
result = GetlastData(data1,data2,p); // 调用 GetlastData 函数计算最终结果
printf("result = %d\n",result);
return 0;
}
指针数组: int * p[4]
就是数组里面所有元素都是一个指针。
注意:
指针函数
int * (p(int a,int b))是一个函数,它的返回值的类型是一个指针类型;
函数指针
int (*p)(int a,int b))是一个指针,它是定义一个指针变量指向一个函数。
例8.25 有a个学生,每个学生有b门课程的成绩。要求在用户输人学生序号以后,能输出该学生的全部成绩。用指针函数来实现。
#include <stdio.h>
// 指针数组
int main(){
int a = 101;
int b = 102;
int c = 103;
int d = 104;
//指针数组
// p[4] = {&a,&b,&c,&d} 表示这四个变量都是一个地址 , * p[4] 对这四个地址取值
int * p[4] = {&a,&b,&c,&d}; //强调的是一个数组
for(int i = 0 ;i <4;i++){
printf("值是%d\n", *(p[i]));
}
return 0;
用函数调用指针数组,打印所有的值
#include <stdio.h>
#include <stdlib.h>
//指针数组
int a = 20;
int b = 45;
int inarr(int a ,int b){
return a > b ?a :b ;
}
int petarr(int a ,int b){
return a < b ?a :b ;
}
int getarr(int a ,int b){
return a + b ;
}
int main(){
int data ;
// (*p)(int a ,int b ); 函数指针
// 定义 函数指针数组,包含三个指向函数的指针
int (* pfunc[3])(int a ,int b ) = {
// pfunc[3] = {inarr,petarr,getarr}表示这四个函数都是一个地址 ,* pfunc[3] 对这3个函数取值
inarr,
petarr,
getarr}; //函数 指针数组
for(int i = 0; i<3;i++){
data =(* pfunc[i])(a,b); // 调用函数指针数组
printf("data = %d\n",data);
}
return 0;
}
指针函数: int * p(int x,inty);
概念:
注意:指针函数
int * p(int a,int b)是一个函数,
它的返回值的类型是一个指针类型;函数指针
int *p(int a,int b)
是一个指针,它是定义一个指针变量指向一个函数。
编程练习:
例8.25有a个学生,每个学生有b门课程的成绩。要求在用户输入学生序号以后,能输出该学生的全部成绩。用指针函数来实现。
#include <stdio.h>
int* GetADDFrom(int position,int (*pa)[4]){
int *p2;
p2 = (int *)(pa+position);
return p2; // 返回一个指针地址
}
int main()
{
int arry[3][4] = {{45,65,94,25},{81,56,63,58},{58,59,57,56}};
int position;
printf("请输入学生位号\n");
scanf("%d",&position);
int *p;
p = GetADDFrom(position,arry); //调用函数
for(int i=0;i<4;i++)
{
printf("%d ",*p++);
}
return 0;
}
例8.26对例8.25中的学生,找出其中有不及格的课程的学生及其学生号。
#include <stdio.h>
// GetAddFrom函数:根据给定的position和二维数组指针p,二级指针p2指向数组中对应行的起始地址
int *GetAddFrom(int position,int (*p)[4])
{
// *p2 = (int *)(p+position);//将父数组的首地址 赋值给 指针 **P2的地址。
int *p2;
p2 = (int *)(p+position);
return p2;
}
int main()
{
int a[3][4] = {{45,65,94,25},{81,56,63,58},{58,59,57,56}};
int position;
int *p;
printf("请输入学生号数\n");
scanf("%d",&position);
p = GetAddFrom(position,a);
for(int i=0;i<4;i++)
{
printf("%d \n",*p++);
}
printf("doen!\n");
for(int i=0;i<3;i++)
{
for(int j = 0;j<4;j++){
if(a[i][j]<60)
{
printf("数据是:%d,第%d行,第%d列, \n",*(a[i]+j),i,j);
}
}
}
return 0;
}
二级(多级)指针(套娃):
如何定义一个二级指针: int **p
编程练习
#include <stdio.h> //引入标准输入输出库
// 二级指针
int main() //主函数
{
int data = 10; //定义一个整型变量 data 并初始化为 10
int *p = &data; //定义一个指针 p 并将其赋值为 data 的地址
printf("data 的地址是%p\n", &data); //打印 data 的地址
printf("P保存 data 的地址是%p,data 的内容是%d\n", p, *p); //打印指针 p 中保存的地址和其所指向的变量的值
printf("p自己的地址是:%p\n", &p); //打印指针 p 自己的地址
/*int *pp; //定义一个指针 pp
pp = &p; //将 pp 的值设置为指针 p 的地址
printf("pp保存p的地址是%p,\n", pp); //打印指针 pp 中保存的值,即指针 p 的地址
printf("*pp保存的地址是%p\n", *pp); //打印指针 pp 中所指向的变量的值,即指针 p 中保存保存 data 的地址
*/
int **p2; //定义一个二级指针 p2
p2 = &p; //将二级指针 p2 的值设置为指针 p 的地址
printf("p2保存的p 地址%p\n", p2); //打印二级指针 p2 中保存的值,即指针 p 的地址
printf("*p2是对p地址中的地址进行打印%p\n", *p2); //打印二级指针 p2 中所指向的变量的值,即指针 p 中保存 data 的地址
printf("**p2是对p地址中的地址中的值进行打印%d\n", **p2); //打印二级指针 p2 中所指向的变量的值,即 data 变量的值
return 0; //程序结束并返回 0
}
编程练习:对例8.25的程序修改,不使用函数指针
#include <stdio.h>
// GetAddFrom函数:根据给定的position和二维数组指针p,二级指针p2指向数组中对应行的起始地址
void GetAddFrom(int position,int (*p)[4],int **p2)
{
// *p2 = (int *)(p+position);//将父数组的首地址 赋值给 指针 **P2的地址。
*p2 = (int *)(p+position);
}
int main()
{
int a[3][4] = {{45,65,94,25},{81,56,63,58},{58,59,57,56}};
int position;
int *p;
printf("请输入学生号数\n");
scanf("%d",&position);
// 调用GetAddFrom函数,传入位置号和数组a的地址,并将得到的地址存储到p指针中
GetAddFrom(position,a,&p); // 传入指针 &p 自己的地址
for(int i=0;i<4;i++)
{
printf("%d \n",*p++);
}
printf("doen!\n");
for(int i=0;i<3;i++)
{
for(int j = 0;j<4;j++){
if(a[i][j]<60)
{
printf("数据是:%d ,第%d行,第%d列,\n",*(a[i]+j),i,j);
}
}
}
return 0;
}
注意:二级指针并不等同于二维数组!
#include <stdio.h>
int main()
{
int a[3][4] = {{45,65,94,25},{81,56,63,58},{58,59,57,56}};
int (*p)[4] = a;
// int **p = a;
printf("p = %p\n",p);
printf("a = %p\n",a);
printf("*a = %p\n",*a); //打印的是列地址,
printf("%p\n",*p); //*p是野指针,不是我们认为的列地址
**p = 100;
printf("%d ",a[0][0]);
/*
因为二级指针并不等同于二维数组,*p是一个野指针,所以当用**p访问二维数组时并不能改变里面的值,
它执行的结果是一个段错误
*/
return 0;
}