C语言——指针篇(二)指针和数组之内存分配和初始化

前言:在上一篇文章中说到了指针变量和普通变量的区别,那么这一篇文章中就来说说指针和数组的关联和区别,它们在很多应用场合中可以互相取代,但也在很多场合中有着自己的无法替代的作用和地位。

数组和指针的内存分配

假设我们有如下代码,分别定义了一个整型数组a和整型指针变量b,假设其编译运行的机器的机器字长为32位,一个int类型占4个字节。

int a[4];  
int *b;
  • 数组的内存分配:对于数组类型的变量,编译器在其声明时就给其分配一块连续的存储空间。编译其首先根据数组的类型和维数,计算这个数组需要占用多大的空间,在这个例子中,数组a需要占用的空间是4x4=16个字节的空间。分配完成后,编译器将该空间首地址与变量a相关联。需要注意的是,此时数组名a代表该数组的首地址,也就是数组第一个元素的地址。并且,当编译器分配完成后,在数组的生存期间(关于生存期的描述可见笔者以前的文章),该数组元素就存放在该地址块,不会改变a的值。因此,对于代表数组首地址的数组名,其实是一个地址常量,也就是指针常量,它可以被销毁,但是不能被重新赋值。
  • 指针的内存分配:对于指针类型的变量,笔者以前提到过,不管它是指向什么类型的变量,它本身的所占的空间小大和程序编译运行的机器字长相关。在这个例子中,我们以32位机举例,以下所有提到的指针变量大小都是32位,即4个字节。所以,编译器会给b分配的存储空间大小为4个字节。

  • Q:既然指针变量的大小在同一机器中是固定的,那为什么还要声明它所指向的类型,如:int,char?
  • A:虽然指针大小在同一机器中是固定的,但是我们无论是用指针进行间接取值还是用+-运算对指针进行移动时,都需要知道我们取几个字节或者移动几个字节。在这个例子中,取值时,在b所指向的地址上连续取4个字节的数据;在使用b++或者b--时,不是单纯的对b的+1或者-1,而是+(1x4)或者-(1x4).

数组和指针的初始化

关于指针和数组的初始化过程,笔者还是结合32位MCU的情况进行介绍,比起强大繁复的PC系统裸机MCU更容易让人理解。

  • 数组的初始化:数组的初始化可分为完全初始化和缺省初始化,二者的区别如下:
int a[5] = {0,1,2,3,4};  //对数组的每个元素都赋了值
int b[5] = {0,1,2};  //后两个元素缺省

上面两种初始化赋值方法,第二种方法缺省的元素,编译器会一致将其赋值为0.

  • 指针的初始化:指针的初始化是将一个地址赋给指针变量,需要注意的是,赋给指针的变量地址所存储的变量类型必须和指针变量的类型相对应。否则,有的编译器能够警告和报错,而有的编译器仅仅给出是警告而已。当指针有指向地址后,可以通过*来间接操作它指向的值。

  • Q:未对数组进行初始化?
  • A:当数组未进行初始化时,编译器会根据它是否为静态变量类型进行不同处理(关于静态变量和自动变量的初始化,可见这篇文章)。如果是静态变量,那么编译器会给该数组所有元素自动初始化为0;如果是自动变量,由于函数堆栈的调用,数组被分配到的内存空间很大几率会是“脏”的,留存着上次使用的数据,对外表现为数组元素都是一些随机数
  • 因此,当我们选择很大数组作为数据结构时,要考虑将它设为自动变量的开销。因为,自动变量数组在每次调用函数时需要对其进行初始化,而这些初始化过程和赋值语句一样需要时间和空间来执行。如果将其设为静态变量,可以大大减少开销。

  • Q:未对指针进行初始化?
  • A:关于指针的初始化也可分为静态变量类型和动态变量类型来讨论。
  • 对于静态变量类型来说,指针声明后,若没有对其初始化,通通把指针指向地址0(这时每个内存单元值都为0,详见这篇文)。在C语言中,也将NULL定义为0x00000000。所以对其赋值NULL的做法也就是将它指向零地址。
  • 对于自动变量类型来说,由于函数调用频繁出入堆栈,指针被分配到的内存单元是也充满着"脏数据"。这时如果未对指针进行初始化就引用,才是真正致命的操作。因为你根本就不知道那些脏数据会指向哪一块内存的地址,以致于引起各种匪夷所思的错误。

  • Q:零地址位于哪里?其内容是什么?
  • A:这里笔者以ARM的Cortex-M0+架构系列的MCU举例。这里的零地址开始的一块连续的存储块,位于Flash闪存区。并且这块存储块存储的是系统的一张中断向量表。该零地址单元存储的是MSP初始值(主存栈顶指针)。将野指针默认指向零地址后,如果后续未赋值而企图操作该野指针,那么逻辑上就是对该零地址进行操作。但是从物理上来说,对Flash中单元的擦写需要遵循一定的时序逻辑,只是简单通过指针访问并不能改变该值,所以这维护了对未初始化指针操作安全性。

总结:关于指针和数组的内存分配,需要考虑的是它们本身元素数据类型和指针数据类型的问题。关于指针和数组的初始化,需要考虑的是它们是静态存储类型还是自动存储类型,不同类型对应编译器自动初始化操作不同。

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