外贸网站电子建设,购物网站开发英文文献,下载一个百度时事新闻,网站服务费怎么做分录引入
在C语言的学习过程中#xff0c;指针是躲不掉的一大困难#xff0c;开始的时候#xff0c;可能你会觉得初始化整形指针和解引用不过如此#xff0c;但是当类型逐渐复杂起来以后#xff0c;没有对指针和类型的深入理解#xff0c;想要看懂和很好的运用指针就比较困难…引入
在C语言的学习过程中指针是躲不掉的一大困难开始的时候可能你会觉得初始化整形指针和解引用不过如此但是当类型逐渐复杂起来以后没有对指针和类型的深入理解想要看懂和很好的运用指针就比较困难了希望通过我的这篇文章让大家对指针能有更好更深入的认识。
指针
指针是什么
在计算机中必不可少的不只是CPU的运算还需要有内存对数据的存储然而在存储数据的过程中必然会面对这样的问题那么多的内存单元数据到底存在哪CPU运算时又要从哪读取数据呢这时候就要想了如果你有一个朋友住在了宾馆让你去找他你会怎么找呢肯定不是一个一个房间敲开找要问道朋友的房间号才能一次性找到他的位置。那么我们是否可以给每个内存都给一个编号呢答案是可以。这便有了指针。 1.内存被划分成一个个的单元一个内存单元大小是一个字节 2.每个内存单元给一个编号这个编号就是地址C语言中简称指针 大概就是以下的换算 内存单元的编号地址指针 指针变量地址
#include stdio.h
int main()
{int a 10;int *pa a;//*说明pa是一个指针变量指向int类型其中存放的是指针也就是a的地址//a表示的是取出a变量的地址然后通过语句赋给pa*pa 20;//此处的*为解引用相当于通过pa存的地址找到a可以理解为*paaprintf(%d %d\n,*pa,a);//此时打印的两值都为20return 0;
}
通过以上的讲解大概认识了指针是个什么东西并且了解了其简单使用了下面专们来讲讲指针变量的大小。 指针变量大小 指针变量专门用来存地址指针变量的大小取决于地址存放所要多大的空间 1.32位机器上地址线32根二进制32bit位要将此地址存起来需要四个字节的空间 2.64位机器同理一个地址需要八个字节 注地址和类型所占的空间不同64位机器就像一个相比32位机器更大的宾馆所需要的编号位数需要更大但是每个房间的大小却不变一样。故int类还是占4个字节的空间只是找到这个空间的编号地址变复杂了而已。 指针变量类型
在刚刚的代码块中我们谈到了int *pa意思是pa是一个指针指向的变量是int类型的数据那我们合理联想一下是不是有int*就有char*long long int*呢答案是是的char *p意思是开辟指向char类型的指针空间long long int*就是指向long long int类型的。前面提到的指针解引用*p中int *p中的*p可以访问4个字节的空间而char *p的*p可以访问1个字节的空间以此类推。
指针加减整数
根据上述指针变量类型我们就可以对指针进行加减运算见下方代码
#includestdio.h
int main()
{int a 10;int *pa a;char *pc (char*)a;//pa 1----地址 4//pc 1----地址 1//以上加减跳过的字节数是以指针类型为依据的注意观察return 0;
}
而在C语言中有数组这样的一种数据类型他的下标随地址的增加而增加且在内存中连续存放那我们是否可以通过指针而非[i]来访问数组元素呢见代码
#includestdio.h
int main()
{int arr[10]{0,1,2,3,4,5,6,7,8,9};int *p arr;//数组名是首元素地址for(int i 0;i 10;i){printf(%d ,arr[i]);} for(int i 0;i 10;i){printf(%d ,*(p i));//上下两块代码打印的结果是一样的其实运行的效果也是一样的} return 0;
}//代码可以CV自测一下
指针减指针
指针减指针得到的是int类型的数据但是相减时一定要满足这样一个条件就是两个相减的指针指向的是同一块空间。eg指向同一个数组里的不同元素这样大指针减小指针便可以得到指针间的元素个数了。
#includestdio.h
int main()
{int arr[10] {1,2,3,4,5,6,7,8,9,10};printf(%d\n,arr[9]-arr[0]);//将打印指针间的元素个数return 0;
}
void类型指针
在指针中有这样一种特殊的指针那就是void*无具体类型指针在用指针变量存放不同类型的地址时不是相同类型的地址是不能相互赋值的要想放入指针变量类型不同的地址只有两个办法一个是强制类型转换另一个便是void*见代码
char a m;
int *p a;//这样写会报错
int *p (int*)a;//将a的地址类型强制转换成int*放入时不报错
void *p a;//将a的地址放入void*类型的p中不报错
void*类型的指针可以放其他任意类型的指针比如char*int*等等虽然放的指针类型很多但还是有一定的局限性 注 1.void*类型不能直接解引用 2.void*类型指针不可加减整数 虽然void*可以包含许多类型的指针但这恰恰让其只知道指向的位置却不知道访问多大的空间故产生以上问题。
加餐const
const使变量有了常属性见下代码
#includestdio.h
int main()
{const int a 10;//给a加上consta 20;//这时修改a的值时编译器就会报错int *pa a;*pa 20;//这时候a的值将被成功改掉pa执政相当于一个后门间接改aconst int *pb a;//给*pb加上const属性*pb 0;//这时候通过*pb来改a时就会报错return 0;
}
其中const虽然有了常属性但本质上还是属于变量范畴通常叫常变量const对于变量只是在语法上做了限制。
当const放在不同位置时起到的作用也是不同的
const int a 10;//不能通过a改变a变量的值
const int *pa a;//不能通过*pa改变a的值但pa指针可以被直接改变
int const *pb a;//pb和pa的性质相同
int *const pc a;//可以通过*pc改变a的值但pc的值不能直接改变
const int * const pd a;//不可通过*pd改变a同时也不能直接改变pd
注意观察其实不难发现根据const所在的位置就可以判断其在哪个变量上做了限制了。
指针关系运算比大小
比的是地址的高低感觉没啥讲的
野指针
我们在C语言学习过程中肯定不免听到别人说“野指针”这三个字现在我们来聊聊野指针吧。
现在我来给大家生成一个野指针
#includestdio.h
int main()
{int *ptr;*ptr 20;//非法访问return 0;
}
其中ptr就是一个野指针也就是所指向不可知地址的指针 由于生成的指针ptr指向方向不定所以在访问或改变其指向的值的时候是极其不安全的因为没有人会知道他指向的是哪一块空间。 避免生成野指针 1.给指针初始化 2.不知道初始化什么给指针赋NULL 3.指针用完记得置NULL 4.避免返回局部变量的地址 在局部变量销毁空间释放后局部变量指针就成为野指针而引发错误 assert断言
如果你在为害怕误用指针而烦恼建议来看看assert吧它能一定程度上帮助你判断指针是否可以使用在assert.h中定义了宏assert();
#includestdio.h
#includeassert.h
int main()
{int *pa NULL;assert(pa ! NULL);//当pa为空指针时报错return 0;
}
传值和传址
在函数调用过程中有时候会遇到传递参数的问题但有时候单纯传递数却无法解决一些问题
比如写一个函数用来交换两个变量的值
#includestdio.h
void Swap1(int x,int y)
{int tmp x;x y;y tmp;
}
void Swap2(int* pa,int* pb)
{int tmp *pa;*pa *pb;*pb tmp;
}
int main()
{int a 10;int b 20;Swap1(a,b);printf(%d %d\n,a,b);//这里将会打印 10 20可以看到变量并没有交换Swap2(a,b);printf(%d %d\n,a,b);//这里打印 20 10变量成功交换return 0;
}
可以看出当要用来改变传递变量的值的时候可以传递它的地址而直接传递其数值就达不到这样的效果。 传址让函数与主调函数建立联系 二级指针
指针的内存用来存放地址数据那么能否创建一个指向指针变量的指针呢
当然可以见代码
#includestdio.h
int mian()
{int a 10;int * p a;//取a的地址int ** pp p;//取指针p的地址pp为二级指针int *** ppp pp;//取二级指针pp的地址ppp为三级指针用的很少//其中**ppaprintf(%d\n,**p);return 0;
}
指针数组
什么是指针数组字面意思存放指针的数组
#includestdio.h
int main()
{int a 10;int b 20;int c 30;int* arr[3] {a,b,c};//其中arr数组的每个元素都为int类型的指针变量return 0;
} 数组指针
也是字面意思指向数组的指针 注在看这些名字的时候可以注意一下它的命名特点和方式比如数组在后其本质就是数组指针在后其就是指针。 int arr[10] {1,2,3,4,5,6,7,8,9,10};
int (*parr)[10] arr;//其中parr是数组指针arr取得是整个数组的指针
//[]的优先级 *
//*代表parr是一个指针而[10]代表parr指向的数组有十个元素每个元素是int类型
//parr 1会跳过整个数组
//用parr访问元素(*parr)[i]
二维数组传参
#includestdio.h
void print1(int arr[3][5],int r,int c){....}//这两种传参方式都对
void print2(int (*arr)[5],int r,int c){....}
int main()
{int arr[3][5];print(arr,3,5);//二维数组传参return 0;
}
函数指针 字面意思指向函数的指针
#includestdio.h
int Add(int x,int y)
{return x y;
}
int main()
{int (*pf)(int,int)Add;int ret (*pf)(4,9);int (*pf2)(int,int) Add;//Add本身就可以作为地址赋给pf2int ret2 (*pf2)(4,9);int ret3 pf(4,9);//调用是pf可不用解引用printf(%d %d %d\n,ret,ret2,ret3);//打印的三个值是相同的return 0;
}
函数指针数组
总的来说其实还是要看名字就是存放函数指针的数组
使用举例
#includestdio.h
int add(int x, int y)
{return x y;
}
int sub(int x, int y)
{return x - y;
}
int mul(int x,int y)
{return x * y;
}
int div(int x, int y)
{return x / y;
}
void menu()
{printf(1.add\n);printf(2.sub\n);printf(3.mul\n);printf(4.div\n);printf(0.exit\n);
}
int main()
{int a, b;menu();int input;int (*parr[5])(int, int) { NULL,add,sub,mul,div };//上面的函数指针数组里分别放了四个函数指针scanf(%d, input);while (input 5 input0) {scanf(%d%d, a, b);int ret parr[input](a, b);//通过调用函数指针数组来间接访问各个函数printf(%d, ret);}return 0;
}
以上的代码完成了一个简单的计算器同时规避了一堆if else的冗杂这便是函数指针数组的一个妙用。
总结
以上讲了指针的基本类型但是关于指针的细节还有很多很多再往后深入就是要注意指针的不同类型和运算才是深入了解和应用指针的关键。那么今天的指针内容就先分享到这里如果感觉对你还有帮助的话记得留一个小小的赞再走哦