C语言指针传递和内存分配

来源:互联网 发布:linux matlab库 编辑:程序博客网 时间:2024/05/21 13:02
1.内存分配方式有三种:
(1) 从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量,static变量。
(2) 在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。这里和Java有很大区别,Java函数调用的内部的存储单元都是在堆上创建的,所以Java需要虚拟机进行GC。
     (在函数中不要返回栈内存,但可以返回动态分配的内存)。
(3) 从堆上分配,亦称动态内存分配。程序在运行的时候用malloc 或new 申请任意多少的内存,程序员自己负责在何时用free 或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。


2.数据类型的本质:

C中没有 byte[] ,所以用usign char*(8bit) 代表 ,其实计算机中并没有char 类型,更准确的说计算机并没有数据类型,数据类型都是编译器定义的,比如 'd'的ascii是100(十六机制的0x64)
内存中存储的0x64(0110 0100),如果你认为它是int,那么它就是100(十进制) ;如果你认为它是char,那么它就是d;如果你认为它是字节,它就是unsign char


3.C的内存模型,指针变量名的本质就是内存地址,以下图为例,区分a+1 和 *a+1,a+1代表的是1002这个内存单元的内容,*a+1存储的是b






4.区分可打印字符串和不可打印字符串:


char[3] a = {'x','y','z'}; //字符数组

char*   a = "xyz";//末尾自动补零,它是可打印字符串

 unsigned char* deviceID = "AA\0AAA";
 printf("%d",strlen(deviceID));   //输出结果为2,但是真实长度是5,被截断了,是不可打印字符串,如果函数要返回deviceID给调用者,需要把deviceID的真实长度返回。

像Base64编码就是可打印的编码,即编码的结果没有'\0',不会被截断的。ASCII 字符是不可打印的。


5、函数返回指针的几种方法(以字符指针为例char *,特别注意返回不可打印的字符指针的问题)

typedef unsigned char byte;void print_char_string(byte *mychar, int len){    int i=0;for(i=0;i<len;i++){printf("%c->0x%x;",mychar[i],mychar[i]);}printf("\n");}


(1) 在调用函数之前可以获知字符串的长度

void test(byte *mychar){mychar[0] = 'a';mychar[1] = 'b';        mychar[2] = '\0';mychar[3] = 'd';mychar[4] = 'e';}int main(){   byte b[5]={0};   print_char_string(b,5);   test(b);   print_char_string(b,5);   return (0);}

(2)在调用函数之前不知道字符串的长度

错误一:C函数调用是在栈上分配的,所以在函数内部定义的局部变量会随着函数调用的结束而出栈销毁,b不会被赋值。即使通过malloc分配内存也是不行的,b一直是NULL

void test(byte *mychar){mychar[0] = 'a';mychar[1] = 'b';    mychar[2] = '\0';mychar[3] = 'd';mychar[4] = 'e';}int main(){   byte *b = NULL;   test(b);   return (0);}


错误二:下面的方法把指针的地址作为参数调用函数,在函数内malloc,用完了由调用者free,但是忽略了字符的返回可能被截断的问题。

void test2(byte *p){p[0] = 'a';p[1] = 'b';    p[2] = '\0';p[3] = 'd';p[4] = 'e';}void test(byte **mychar){*mychar = (byte *)malloc(sizeof(byte) * 5);    memset((void*)(*mychar), 0, 5);byte* p = *mychar;test2(p);}int main(){   byte *b = NULL;   test(&b);   print_char_string(b,strlen(b));//a->0x61;b->0x62;,因为b字符串包含了不可打印字符,造成了截断   free(b);   return (0);}


正确方法一:

void test2(byte *p){p[0] = 'a';p[1] = 'b';    p[2] = '\0';p[3] = 'd';p[4] = 'e';}int test(byte **mychar){*mychar = (byte *)malloc(sizeof(byte) * 5);    memset((void*)(*mychar), 0, 5);byte* p = *mychar;test2(p);return 5;}int main(){   byte *b = NULL;   int length = test(&b);   print_char_string(b,length);   free(b);   return (0);}

正确方法二:

通过函数返回值来传递动态内存,但是这个方法不能解决返回的字符串包含不可打印字符的问题,
byte* test3(){   byte *p = (byte *)malloc(sizeof(byte) * 5);    memset((void*)(p), 0, sizeof(byte) * 5);p[0] = 'a';p[1] = 'b';    p[2] = '\0';p[3] = 'd';p[4] = 'e';return p;}int main(){   byte *b = test3();   free(b);   return (0);}

需要注意的是返回值只能是动态分配的内存,如果是函数内的局部变量千万不要通过函数返回值,虽然可以返回,但是由于是在栈上分配的,所以可能会被下面的调用覆盖。

0 0
原创粉丝点击