C语言中的指针——C之精髓?

大神们经常说C语言是一种底层语言,不像python啊,java啊这种高级编程语言。一直理解的不大好,也不明白为啥C语言就底层了。只是觉得老拿C语言做单片机嵌入式的开发,是不是就是底层了。最近看数据结构和算法,一会一个指针一会一个指针的总是弄混,感觉对指针有一种若即若离的感觉,既陌生有熟悉。决定重新回过头来看他。

1指针

  • 地址和指针有着千丝万缕的关系,计算机内存中的每个位置都有一个地址标识,C语言中用指针来表示地址,声明一个指针变量并不会自动给他分配任何内存。在对指针进行间接访问前,指针必须初始化:要么指向现有内存(赋值),要么动态分配新的内存(malloc)。
  • C标准定义了NULL指针,它作为一个特殊的指针常量,表示不指向任何位置,因而对一个NULL指针进行解引用操作同样也是非法的。因而在对指针进行解引用操作的所有情形前,如常规赋值、指针作为函数的参数,首先必须检查指针的合法性- 非NULL指针。
  • 所有的指针进行显示的初始化是种好做法

如果知道指针被初始化为什么地址,就该把它初始化为该地址,否则初始化为NULL
在所有指针解引用操作前都要对其进行合法性检查,判断是否为NULL指针,这是一种良好安全的编程风格

1.1指针运算

  1. 自增自减:指向下一个地址或指向上一个地址
  2. 同类型指针相减:如果两个指针指向同一个数组,相减的结果就是两个指针之间的元素数目。注意:指针相加没有意义;不同类型的指针相减也没有意义
  3. 指针加上或减去一个整型值:如一个float类型的指针加3表示指针的值增加3个float类型的大小。
  • 如果对一个指针进行减法运算,产生的指针指向了数组中第1个元素前面的内存位置,那么它是非法的。
  • 加法运算稍微不同,如果产生的指针指向了数组中最后一个元素后面的那个内存地址,它是合法的,但不能对该指针执行解引用操作,不过之后就不合法了(这和STL中迭代器尾部元素可指向尾部元素的下一个位置是一样的道理)

插播:typedef 和#define有什么区别呢?

#define 是预处理指令,在编译预处理时进行简单地替换 ,不做正确性检查。

#define A 3+4
在程序中遇到3*A则会将A进行简单的替换->3*3+4=13
再例如:
#define int_ptr int* int_ptr a,b; //a是int*类型的,而b是int型的
typedef int* int_ptr int_ptr a,b; //a和b都是int*类型的

typedef是在编译时处理的,他是在自己的作用域里给一个已经存在的类型一个别名。

typedef char ElemType 把一个char型起一个别名叫ElemType,这样的好处是,当你想将程序中的数据类型换成int型的时候,不用一个一个修改,只需修改typedef char ElemType为typedef int ElemType即可。

1.2void *指针

C中提供一个特殊的指针类型: void *,它可以保存任何类型对象的地址。
void *表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。void *指针只支持以下几种操作:

  • 与另一个指针比较
  • 给另外一个void *指针赋值
  • void *指针当函数参数或返回值
    不允许使用void *指针操作它指向的对象,值得注意的是函数返回void *类型时返回一个特殊的指针类型,而不是向返回void 类型那样无返回值。

1.3函数指针和指针函数

  • 函数指针 int* f(int a, int b):本质是个指针,它指向的是函数,指向函数的指针包含了函数的地址,可以通过它来调用函数。
  • 指针函数 int (*f)(int a, int b):本质是个函数,它的返回值是某个类型的指针

2 数组和指针

知乎上有个大神说:在软开行业里有一句话叫没有什么是不能通过增加一个抽象层解决的。比如说,数组就是对“一系列连续内存单元”的抽象,它的外观表现为“一个固定大小的容器”知乎连接。从这个角度上来理解,似乎数组比指针更“高级”一些,指针相对更底层。

指针和数组的爱恨情仇

2.1数组名

  1. 声明时:数组的属性和指针的属性不同,在声明数组时,同时分配了用于容纳数组元素的空间;而声明一个指针时,只分配了用于容纳指针本身的空间。
  2. 表达式中:需要注意,数组名是指向数组第一个元素的首地址,其本质是一个常量指针(常指针),指针自身的值不能被改变,如声明一个数组:int arr[3]={1,2,3},则不能出现arr++,或arr+=3这类语句。但是可以有int num=*(arr+2)指向第三个元素
  3. 通过数组名引用数组元素时:改变第二个元素的值为100,arr[1]=100;当使用[]的方式引用数组元素时,在编译器中都会转换成指针的形式操作,arr+1和&arr[1]是一样的,都表示第二个元素的首地址。
  4. 作为函数参数:不管以指针的形式还是数组名的形式作为函数的参数时都会被转换成指针。
    void array_to_pointer(int *ia){……}  //无需转换
    void array_to_pointer(int ia[ ]){……}  //被转换成*ia
    void array_to_pointer(int ia[100 ]){……}  //被转换成*ia
void array_test(int ia[100])//ia被转换成了指针不再是常指针了!!!
{
  double da[10];
  printf("%d", sizeof( ia ));
  ia++;      //没错误,按指针进行处理而非数组名
  //da++;   //编译错误,数组名是常指针
}

2.2指向数组的指针

指向数组的指针主要是用来对二维数组进行操作的。
理解一下 int (*p)[100]:由于括号的优先级是最高的,所以首先执行解引用,表明了p是一个指针,接下来是数组下标的引用,说明p指向的是某种类型的数组,前面的int表明p指向的这个数组的每个元素都是整数。
当对一个一位数组的数组名取&操作时,返回的是一个指向数组的指针。
例如:
int arr[100]={0};//声明一个数组
int *p=&arr;//一个指向数组的指针
int *q=arr; //arr是数组的首地址,q指向了数组的第一个元素

2.3指针数组

在声明一个指向数组的指针时千万不要丢到那个括号,如:int (*p) [100]; 如果丢掉了括号那就完全改变了意图,从而意外地声明了一个指针数组。
指针数组就是一个数组他的所有元素都是指针。

int (\*p)[100];//指向数组的指针
int* p[100];//指针数组,以p为数组名的数组中存放的都是指针元素

插播:指针常量和常量的指针...

常量指针: const char* ptr ="hello"; char const* ptr="hello";内容不能改,指针可改
指针常量: char* const ptr="hello"; 指针不能改,内容可改
指向常量的常指针:const int* const p;指针和内容都不能改

带两个const 的好区分,就是都不能改。怎么区分指针常量和常量指针呢?
1. 看const 和*的排列顺序

int const* p;   const * 即常量指针
const int* p;   //const * 即常量指针
int* const p;   //* const 即指针常量

2. 看const离谁近,即从右向左看

int const* p;   //const修饰的是*p,即*p的内容不可通过p改变,但p不是const,p可以修改,*p不可修改;
const int* p;   //同上
int* const p;   //const修饰的是p,p是指针,p指向的地址不能修改,p不能修改,但*p可以修改;

以上只是关于C语言指针的一些皮毛,剩下的东西后续再补充。通过今天的学习,对C语言底层的地位有了新的认识,大概是他因为跟硬件层息息相关。指针的存在让程序员可以自由地对内存进行操作,C语言赋予了程序员极大地自由的同时也带来了极大的隐患。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,422评论 3 44
  • void* 类型指针:通用变体类型指针;可以不经转换,赋给其他指针,函数指针除外;malloc返回的就是void*...
    冰吉凌阅读 3,307评论 0 18
  • 转自CSDN博客 原文链接:http://blog.csdn.net/xinyuwuxian/article/de...
    傻彬儿阅读 718评论 0 0
  • 姓名:周立 zhou li 公司:宁波大发化纤有限公司 【日精进打卡第104天】 【知~学习】 (六项精进)大纲...
    周立zhouli阅读 99评论 0 0
  • 清早,随着拥挤的人群踏上地铁一号线的列车。刺骨的冷气在进入车厢的瞬间,就覆盖了整个身体。所有的汗毛都随寒意树立起...
    无边的蓝海阅读 459评论 0 1