字符数组初始值,字符数组可以存放字符串吗

  

  对内存分区的初步了解如下图,内存分区示意图。一般来说,内存主要分为代码区、常量区、静态区(全局区)、堆区和栈区。   

  

  默认分配的ROM区是只读的,不能修改,即存储代码区和常量区。   

  

  默认分配的RAM区域是读写区域,存储静态区域、堆栈区域和堆区域。芯片的内部分区如下图所示:   

  

     

  

  代码区:存储程序的代码,也就是CPU执行的机器指令,它是只读的。   

  

  常量区:存储常数(程序运行过程中不能改变的量,如: 10,字符串常数“abcde”,数组名等。).   

  

  静态区(全局区):静态变量和全局变量的存储区域是相同的。一旦分配了静态区的内存,在所有程序完成之前,静态区的内存不会被释放。   

  

  堆区:如果一个程序员主动申请调用malloc()函数,他需要使用free()函数来释放内存。如果他申请了堆内存,后来忘记释放内存,很容易造成内存泄漏。   

  

  栈区:存储函数的局部变量、参数和返回值。栈区数据的范围结束后,系统会自动管理栈区内存(分配内存和回收内存),不需要开发者手动管理。   

  

  代码区代码区内存是存储:程序中函数的已编译cpu指令代码区的地址,由系统控制。程序的入口地址,程序名和函数名也是指针。可以查询函数名所在的内存地址,查询存储函数的区域。int main(int argc,const char * argv){ printf(' main :% p \ n ',main);返回0;}打印结果如下,证明这个地址区确实在代码区。   

  

  Main:0x100003f50恒定面积char * p=" abcdef   

  

  这段代码和char * p;p=" abcdef是等价的。   

  

  上面两个定义的具体含义是:定义一个char *类型的指针P,其中P存储字符串常量“abcdef”的第一个地址,字符串常量“abcdef”存储在常量区,即P指向常量区。那么p所指区域内的内容是无法修改的。只能用*p来读取p所指向的内容,当然也可以去掉指针p指向其他区域。   

  

  测试如下:   

  

  void测试(void){ char * p=' abcdef ';printf('0x%p: %s\n ',p,p);//打印指针P的地址和P指向的字符串内容p=' qwedmaprintf('0x%p: %s\n ',p,p);//打印指针P的地址和P指向的字符串内容p0=' 1//尝试将p指向的第一个字符Q改为1 printf('0x%p: %s\n ',p,p);//打印指针P的地址和P指向的字符串内容}打印结果如下   

  

  0x 10000: abcdef0x100003fa73360 qwedma(LLDB)可以看出,ABCDEF字符串常量存储在0x100003f96区,P指针指向该区,P指针从指向qwe DMA字符串常量的第一个地址0x 100003 fa 7中去掉。当试图修改P指向的第一个字符,即将qwedma改为1WEDM MA时,发现编译器报错,常量区内容无法更改。   

  

  继续读下面这句话Charstr=" ABCD这句话定义了一个字符数组,但是这个str数组存储在堆栈区,然后把字符串常量“abcd”复制到堆栈区的str数组中,那么这个时候的str就可以修改了。   

  

  void test(void){ char str=' ABCD ';printf('%p: %s\n ',str,str);str0=' eprintf('%p: %s\n ',str,str);}打印结果如下   

  

  0x ffee FBFF 50 b 3360 ABCD0x 7 ffeefbff 50 b 3360 ebcd可以看出str是指向堆栈区的地址:0x7ffeefbff50b,所指向的内容可以修改。第一个字符A被修改为e。   

  

  静态区域(全局区域)静态int a;int c;void test(void){ static int b=1;b;printf('b:%p: %d\n ',b,b);} int main(){ printf(' a :% p :% d \ n ',a,a);printf('c: %p: %d\n ',c,c);   

for(uint8_t i=0;i<5;i++) { test(); } return 0;}打印结果如下

  

a: 0x100008014: 0c: 0x100008018: 0b:0x100008010: 2b:0x100008010: 3b:0x100008010: 4b:0x100008010: 5b:0x100008010: 6静态全局变量,b静态局部变量,c是全局变量,它们都存放在静态区;a和c并未初始化,打印出来都是0,说明编译器自动把他们初始化为0;b在for循环中初始化5次,但实际效果是b仅初始化一次,后面每次调用b都是上次的值,且b的地址一直是不变的,编译器只会为第一次初始化的b分配内存,后面4次初始化是无效的。

  

堆区堆区是调用malloc函数来申请内存空间,这部分空间使用完后需要调用free()函数来释放。
void * mallc(size_t);函数的输入是分配的字节大小,返回是一个void*型的指针,该指针指向分配空间的首地址,void *型指针可以任意转换为其他类型的指针。

  

void test(void){ int *p1=malloc(4);//申请4字节的空间 *p1=123;// 该空间赋值123 printf("%p:%d\n",p1,*p1); printf("%p\n",&p1); free(p1); printf("%p:%d\n",p1,*p1); p1 = NULL; printf("%p\n",p1);}int *p1=malloc(4);语句是申请了4个字节的空间,空间的首地址赋给指针p1,这个首地址存在是堆区;

  

printf(“0x%p\n”,&p1);指针p1本身也是需要存放的,p1本身是存放在栈区的;

  

free(p1);内存释放函数 free(开辟的内存的首地址) ,将内存标记为可用且将里面的内容清空为0,但指针p1还是指向这片空间。比较安全的做法是p1 = NULL;把p1指针释放,避免造成野指针。

  

p2的地址是大于p1的地址,验证堆区是向上生长的,后申请的空间地址会依次增加。

  

栈区栈区由编译器自动分配释放,存放函数的参数值、返回值和局部变量,在程序运行过程中实时分配和释放,栈区由操作系统自动管理,无须手动管理。栈区是先进后出原则,即先进去的被堵在屋里的最里面,后进去的在门口,释放的时候门口的先出去。

  

void test(void){ int a; int b=0; printf("a:%p:%d\n",&a,a); printf("b:%p:%d\n",&b,b);}打印结果如下

  

a:0x7ffeefbff50c:0b:0x7ffeefbff508:0可以看到后定义的局部变量b地址是比a小的,即栈区是向下生长的;

  

a变量没有进行初始化,打印出的a是垃圾值,编译器不会把局部变量初始化为0。但是,需要注意:如果你运行于debug调试模式,运行时机制会把你的栈空间全部初始化为0,这就是解释了为什么平时在debug时看到的未初始化的局部变量初始值是0.

  

使用局部变量时,尽量要先进行初始化,避免垃圾值造成错乱。

相关文章