数组与指针

数组与指针是内存管理的关键,也是C/C++中较难掌握的的地方。现在对其进行一些分析与总结。
 
 一。内存分配方式有四种:

        1.从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的
          整个运行期间都存在。例如全局变量,static 变量,即使是局部static变量(即函数内部定义的static变量)。
          如:
          const char *func()
          {
               static char res[256]={0};
               ...
               return res;  // this is correct.
          }


        2.在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函
         数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集
         中,效率很高,但是分配的内存容量有限。
          const char *func()
          {
               char res[256]={0};
               ...
               return res;  // this is wrong.
          }
 


       3.从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多
          少的内存,程序员自己负责在何时用free 或delete 释放内存。动态内存的生存期
          由我们决定,使用非常灵活,但问题也最多。堆内存的释放必须用free或delete显式释放,
         否则要等到程序结束后由操作系统负责收回。
         const char *func()
          {
               char* res=new char[256];
               ...
               return res;  // this is correct.
          }
 
      4.文字常量区。常量就放在这里,即使是局部定义的常量也放在文字常量区,内容不可以被更改,如常量字符串,一直到程序结束后才由系统释放。例如:
                const int* func(void)
                {
                    const int x=2;
                    return &x;
               }


              const int *y=func();
              cout<<*y<<endl;// result is 2.
 
 
二。数组与指针的特点分析:


        数组的特点分析:


        1.数组长度必须在编译时确定;
        2.数组长度不可变;
        3.数组存在于栈中,只在定义它的语句块内存在;
        4.数组名表示数组第一个元素的地址(它也是指针,也是迭代器,但只能作为右值),但是用sizeof操作符计算其大小是该数组所占的字节数,而不是数组名本身的字节数,唯一的例外是当数组作为函数的参数传递时,数组名自动退化为同类型的指针。例如:
           int a[10];
           cout<<sizeof(a)<<endl;// result is 40
           void func(int  a[10])
           {
               cout<<sizeof(a)<<endl;//result is 4
           }
           动态分配数组返回的指针的特点分析:


           1.数组长度在编译时不需要知道;
           2.一旦分配,数组长度不可变;
           3.存在堆中,除非显示地释放,它一直存在,即使程序已经结束;
           4.无数组名,只有返回的指针。该指针跟一般指针完全一样,如用sizeof 操作符计算其大小,得到是该指针所占内存(32位系统中,指针占4位),而不是其指向的数组所占的内存。如:
            int a[10];
            int *p=a;
           cout<<sizeof(p)<<endl;// result is 4
            p=new int[10];
            cout<<sizeof(p)<<endl;// result is 4
 
          一般指针的特点分析:


          C/C++中无法知道指针所指内容的内存容量,而只能知道指针本身所占的内存。
          sizeof( 指针名)永远为4(在32位系统中),而不管指针指向的是不是数组,指向的内存在堆内还是在栈内。
 
三。C-风格字符串:


        1.C风格字符串:
           以空字符null结束的字符数组即为C风格字符串。
        2.字符串字面值:
            (1)类型:const char*,即不可更改的字符串。
            (2)存储位置及生命期:存储在文字常量区,一直到程序的结束。
            (3)与数组关系:可以初始化(const char 或char型)数组,实质就是拷贝初始化,因此初始化后数组与文字常量区中的该字符串字面值无关了。
                      如:char a[]="hello world";
                              a[0]='s';// ok
                      又如:
                      char *GetString(void)
                      {
                          char p[] = "hello world";
                          return p; // 编译器将提出警告
                      }
                     char *str = NULL;
                      str = GetString(); // str 的内容是垃圾,注意函数返回后,str不为NULL,但其指向的栈内存已经被释放了。
                    
 
            (4)与指针关系:可以初始化或赋值给const char* 或char* 类型的指针,此指针指向的是文字常量区中的字面值常量的地址,因此不可以通过该指针修改其内容,
                      而且其内容和地址知道程序结束均不变。
                     如:char *p="hello world";
                              p[0]='s';// error
                    char *GetString(void)
                      {
                          char *p = "hello world";
                          return p;                      
                      }
                     char *str = NULL;
                      str = GetString(); // str 的内容是"hello world", 但注意str指向的是文字常量区里字面值的指针。
 
        3.C风格字符串的标准库函数:
            标准库strting.h里的以str开头的函数均是C风格字符串的标准函数。
            这些函数要求C风格字符串:以NULL结尾的字符数组,接受char型数组名或char*型指针。
        4. strlen与sizeof 的区别:
           (1)strlen 只接受char* 型指针或char型数组名,而sizeof 接受任何类型的对象或任何类型名;
           (2)strlen对char* 指针和char型数组名是完全一样的,而sizeof 对指针和数组名是不一样的:对指针结果为4,对数组名结果是该数组所占的内存空间;
           (3)strlen计算C风格字符串的长度,不包括最后的null字符,而sizeof对char型数组名计算的长度包括最后的Null字符。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章