您的位置:首页 > 编程语言 > C语言/C++

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

2016-10-24 15:19 405 查看
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);
}


需要注意的是返回值只能是动态分配的内存,如果是函数内的局部变量千万不要通过函数返回值,虽然可以返回,但是由于是在栈上分配的,所以可能会被下面的调用覆盖。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: