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类型的指针.感觉很奇怪,为何要将一个指针 ...
随机推荐
- 深入理解java虚拟机,GC参考手册
深入理解java虚拟机 一.<深入理解Java虚拟机> 1.第2章 Java内存区域与内存溢出异常 2.第3章 垃圾收集器与内存分配策略 3.第4章 虚拟机性能监控与故障处理工具 4.第5 ...
- vim自动添加C C++ sh文件头
set foldenable set foldmethod=manual set fencs=utf-8,ucs-bom,shift-jis,gb18030,gbk,gb2312,cp936 set ...
- Java POI 导出EXCEL经典实现
import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; i ...
- for循环实现的一些小例子
1.1-10阶乘和 package HELLO; public class exercise5 { /** 1-10阶乘和 */ public static void main(String[] ar ...
- Codeforces Round #627 (Div. 3) F - Maximum White Subtree(深度优先搜索)
题意: n 个点 n - 1 条边的树,问每个点所在所有子树中白黑点数目的最大差. 思路: 白点先由下至上汇集,后由上至下分并. #include <bits/stdc++.h> usin ...
- hdu 6806 Equal Sentences 找规律
题意: 给你一个有n个单词的单词串S,对这n个单词进行排列组合形成新的一个单词串T,如果在S中任意某个单词所在位置,和这个单词在T中所在位置之差的绝对值小于等于1,那么就说S和T串相等 让你求S一共有 ...
- Alice's mooncake shop HDU - 4122 单调队列
题意: 有n个订单和可以在m小时内制作月饼,制作月饼不考虑时间(即,你可以在一个时刻在所有需要的月饼都做完) 接下来是n个订单的信息:需要在mon月,d日,year年,h小时交付订单r个月饼 接下来一 ...
- Poj-3922 A simple stone game(k倍动态减法)
题意: 游戏是这样的:两个玩家以一堆n个石头开始游戏.他们轮流从石堆里取石头,每次至少取一块.先走的人第一步最多可以拿n-1块石头.从那时起,一个玩家最多可以拿k倍于他的对手上次拿的石头.例如,如果一 ...
- Codeforces Round #501 (Div. 3) D. Walking Between Houses (思维,构造)
题意:一共有\(n\)个房子,你需要访问\(k\)次,每次访问的距离是\(|x-y|\),每次都不能停留,问是否能使访问的总距离为\(s\),若能,输出\(YES\)和每次访问的房屋,反正输出\(NO ...
- js--执行上下文和作用域相关问题
前言 如果你是或者你想成为一名合格的前端开发工作者,你必须知道JavaScript代码在执行过程,知道执行上下文.作用域.变量提升等相关概念,并且熟练应用到自己的代码中.本文参考了你不知道的JavaS ...