C语言指针基本知识
对程序进行编译的时候,系统会把变量分配在内存单位中,根据不同的变量类型,分配不同的字节大小。比如int整型变量分配4个字节,char字符型变量分配1个字节等等。被分配在内存的变量,可以通过地址去找到,内存区每一个字节都有一个编号,地址也可以形象的理解成我们生活中的住址,通过住址找到每一个人所在的地方。指针作为一个变量用来存放地址,可以通过指针来改动变量。
上图就是一个简单的定义一个一级指针变量和利用指针改变变量数值的过程。int*表示整型指针,*p表示解引用操作,就是利用指针找到a的地址然后再改变a的值。
地址用%p打印,用十六进制表示,在打印时候输入指针变量p和取地址a得出的结果是相同的,证明了指针是用来存放地址的。
指针作为一个变量是有大小的,其大小在32位平台是4个字节,64位平台上是8个字节,大小与指针的类型无关。
上图以32位平台举例子,可以看到无论指针是整型、字符型、浮点型也无论一级指针还是二级指针,其在内存空间所占的大小都是4个字节。
指针有多种类别,按照级数来分便可以分为一级指针,二级指针,三级指针等等
一级指针是最基础的指针,指向的是创建的变量的地址。就类似于上图的前三个sizeof后面所写的。前文讲到指针也是一个变量,是用来存放地址的。既然是一个变量,就也要在内存开辟空间,开辟了空间就也会产生属于指针变量自己的地址。二级指针便是用来存放一级指针地址的。以此类推多级指针也是如此。
指针也可以根据指针指向的变量的数据类型来进行分类,有整型指针,字符指针,数组指针,函数指针等等
整型指针和字符指针
这两个是比较常见和容易理解的指针,依次用int*和char*表示,他们的区别在于指向变量类型不同,内存也不一样,在进行解引用操作时访问的字节大小也因为变量类型的区别会有所差异。整型指针可以访问4个字节,而字符指针只能访问1个字节。也就是说对整型指针变量解引用,一次可以操作一个整型,而对字符变量解引用一次只能操作一个字符。
较为特殊的char*p="hello"这并不是将整个字符串的地址传个了p,而是传了字符穿首元素‘h'的地址,可以通过’h‘的地址来找到整个字符串。此时出现char*p2=“hello”,p2和p代表的是同一处地址,因为hello是常量字符串,没有必要开辟两块不同的空间的来存储它。这是字符指针的一个特性。
void型指针
void型的指针可以接受任何类型的地址,但是不能对void型指针进行解引用操作。解引用操作要有特定的访问字节的数量,比如对整型指针解引用就是访问4个字节,字符型指针解引用就是访问1个字节,而void型指针无法确定访问字节个数,所以不能进行解引用操作。同时void*这种类型的指针也不能进行加减整数的操作,因为无法确定跳过的字节个数。
此图表示了void型指针可以接受任意类型的地址。
数组指针
这是一种指向数组的指针,例如int(*p)[10]这就是一个指向数组的指针,它指向的数组有10个元素,每个元素都是整型。给*p加上括号是因为p和[10]优先结合,这样的话就变成了一个数组而不是指针了。这个数组叫指针数组,int*p[10]这样的写法意思是一个有10个元素的数组,每一个元素都是整型指针,这和数组指针是两个不同的东西。
指向数组的指针里面存放的便是数组的地址,而非数组某个元素的地址,所以在定义数组指针时要用 &+数组名,而不是简单使用 数组名。
上图显示出&arr和arr的不同,虽然起始地址相同,但arr+1只让指针向后移动了一个元素的空间,而&arr+1让指针移动了一个数组的空间。
函数指针
函数指针顾名思义就是指向函数的指针,每个函数都有一个入口,这个入口的地址便是函数指针所指向的地址。函数地址的表示方法为 函数名或 &+函数名。例如一个函数叫Add,&Add和Add都是表示这个函数的地址没有什么差别。函数指针的写法是 函数的返回类型(*)(函数的参数),例如函数Add,其函数指针的写法就是int(*p)(int,int)=Add 。*p要加上括号来保证*和p的优先结合来形成一个指针变量,如果不加括号来优先结合,则会出现int* p(int,int)这样的写法,这就变成了函数的声明,这个函数的返回类型是int*,函数的名字叫p,函数的参数是2个整型和原先的函数指针不是同一个意思。
用函数指针调用函数时可以不加*这个解引用符号,因为这个符号将不会在程序运行的时候起到作用。
上图显示了*这个解引用符号在函数指针调用函数时候不起作用,以上的写法都可以用。
根据函数指针的相关知识,可以来看这两段代码。
代码1中间的 void(*)()是一个函数指针类型,将这个函数指针类型放在括号中,是强制类型转换的意思也就是把0强制转换成一个函数指针,强制类型转换这个部分简单写出来就是“(函数指针)0”是将0作为一个函数的地址,而最外层的括号(*函数的地址)()这个是解引用操作,也就是通过0这个地址,找到了0地址处所在的函数,并且进行调用。
代码2 内部的(int,void(*)(int))这一段表示的函数的参数,第一个参数是一个整型,第二个参数是一个函数指针类型,这个函数指针指向的函数的返回类型是void,参数类型是int。而这个函数的名字就是signal。解决了这个部分的内容,剩下的就是void(*)(int),去除里面的signal函数可以很明显地看出来这是一个函数指针。一个函数由三部分组成,返回类型,函数名,函数的参数。也就是说参数和函数名去掉之后,函数声明中就只剩下一个返回类型。此时,函数名和参数已经在前一步分析中得出,剩下的void(*)(int)便就是函数的返回类型,这个函数返回类型是也是一个函数指针。
这两个代码来自于书本《C陷阱和缺陷》。
函数指针和数组的结合实例,简易的计算器,这是函数指针数组的应用
数组传参
数组在传参的时候传的是首元素的地址,数组名表示首元素的地址。函数的形参可以用数组形式表示也可以用指针形式表示。
一维数组的传参比较简单,例如int arr[3]这个数组,形参可以直接使用int arr[]或者int arr[3]用数组形式表示形参,形参处的元素个数可以写也可以不写,因为元素个数在这里不起作用。或者用一级指针表示,int* arr这样就反映了指针传参传的是首元素地址。
二维数组传参相对比较复杂,由数组的知识可以知道,二维数组必须有规定的列数,所以要以数组形式传参的时候列数不能省略。
以指针形式传参,数组名仍然是首元素地址的意思,作为一个二维数组,首元素便是第一行的数组。比如int arr[3][5]这个二维数组的首元素是一个含有5个整型元素的数组,所以在传参的时候传的指针也应该是指向这个数组的指针。所以此时形参应该表示为int (*arr)[5],这表示一个数组指针,指向一个含有5个整型元素的数组,符合正确的传参规则。
回调函数
回调函数是把函数指针作为参数传给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由函数实现方直接调用,而是用另外一方或者特定条件下来调用。
比较常见的例子就是C语言里面的库函数快速排序,这里需要自己实现的比较函数,就用到了回调函数,int_cmp作为函数的指针充当了qsort的参数。
模拟实现qsort快速排序函数,冒泡排序的推广
C语言指针基本知识的更多相关文章
- C语言指针入门知识
C语言指针往往是C语言学习过程中最困难的地方, 最近重新理解了一下C语言的指针知识, 在此整理一下, 如果有错误请留言指正. 对于刚入门的人来说, 指针涉及方方面面, 从简单的数组到结构体, 都会用到 ...
- C语言指针和数组知识总结(上)
C语言指针和数组知识总结(上) 一.指针的基础 1.C语言中,变量的值能够通过指针来改变,打印指针的语句符号可以是: %08x 2.指针的本质 指针的本质就是变量,那么既然是变量,那么一定会分配地址 ...
- C语言-指针
C指针基础知识 C语言中,指针无疑是最令人头疼的.今天无事就来学学C语言的指针,在此留下点笔记,仅供个人参考. 首先要搞懂的是,指针是什么? 指针:是用来存放内存地址的变量. 不管是什么类型的指针,存 ...
- [转]C语言指针学习经验总结浅谈
指针是C语言的难点和重点,但指针也是C语言的灵魂 . 这篇C语言指针学习经验总结主要是我入职以来学习C指针过程中的点滴记录.文档里面就不重复书上说得很清楚的概念性东西,只把一些说得不清楚或理解起来比较 ...
- C语言指针学习
C语言学过好久了,对于其中的指针却没有非常明确的认识,趁着有机会来好好学习一下,总结一下学过的知识,知识来自C语言指针详解一文 一:指针的概念 指针是一个特殊的变量,里面存储的数值是内存里的一个地址. ...
- (转载)c语言指针学习
前言 近期俄罗斯的陨石.四月的血月.五月北京的飞雪以及天朝各种血腥和混乱,给人一种不详的预感.佛祖说的末法时期,五浊恶世 ,十恶之世,人再无心法约束,道德沦丧,和现在正好吻合.尤其是在天朝,空气,水, ...
- c语言指针学习【转】
前言 近期俄罗斯的陨石.四月的血月.五月北京的飞雪以及天朝各种血腥和混乱,给人一种不详的预感.佛祖说的末法时期,五浊恶世 ,十恶之世,人再无心法约束,道德沦丧,和现在正好吻合.尤其是在天朝,空气,水, ...
- 关于C语言指针的一些新认识(1)
Technorati 标签: 指针,数组,汇编,C语言 前言 指针是C语言的精华,但我对它一直有种敬而远之的感觉,因为一个不小心就可能让你的程序陷入莫名其妙的麻烦之中.所以,在处理字符串时,我总是能用 ...
- C语言指针转换为intptr_t类型
1.前言 今天在看代码时,发现将之一个指针赋值给一个intptr_t类型的变量.由于之前没有见过intptr_t这样数据类型,凭感觉认为intptr_t是int类型的指针.感觉很奇怪,为何要将一个指针 ...
随机推荐
- scala的隐式转换学习总结(详细)
一,隐式转换函数 1, 格式, implicit def 函数名(参数):返回值类型={ //函数体 //返回值 } 2,例子: //导入对应的规则类,以免出现警告 scala> import ...
- nginx反向代理signalr
asp.net core应用常常要通过nginx来反向代理, 普通的web api配置asp.net core反向代理比较常见, 如果在应用中集成了signalr, 如何使用nginx来反代呢? ng ...
- Workflow任务流发布不了
依赖的工作流要发布
- HDU5691 Sitting in Line【状压DP】
HDU5691 Sitting in Line 题意: 给出\(n\)个数字,有些数字的位置固定了,现在要求把所有没固定的数字放在一个位置,使得任意相邻两个位置的数字的相乘的和最大 题解: \(n\) ...
- Codeforces Round #653 (Div. 3)
比赛链接:https://codeforces.com/contest/1374 A. Required Remainder 题意 给出 $x, y, n$,找到最大的整数 $0 \le k \le ...
- zjnu1730 PIRAMIDA(字符串,模拟)
Description Sample Input 6 JANJETINA 5 1 J 1 A 6 N 6 I 5 E Sample Output 1 0 2 1 1 题意:给你一个长度小于等于10^6 ...
- K - Japan(线段树)
Japan plans to welcome the ACM ICPC World Finals and a lot of roads must be built for the venue. Jap ...
- c++派生类中构造函数和析构函数执行顺序、判断对象类型、抽象类、虚函数
一. 代码: 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include&l ...
- 吉哥系列故事――恨7不成妻 HDU - 4507
题目: 单身! 依然单身! 吉哥依然单身! DS级码农吉哥依然单身! 所以,他生平最恨情人节,不管是214还是77,他都讨厌! 吉哥观察了214和77这两个数,发现: 2+1+4=7 7+7=7*2 ...
- 【luogu AT3957】[AGC023F] 01 on Tree
01 on Tree 题目链接:luogu AT3957 题目大意 有一棵根为 \(1\) 的树,每个节点有个值 \(0\) 或 \(1\). 然后每次你可以把一个没有父亲的点删除,然后把值放进一个数 ...