这个板块只要针对个人所遇到的一些问题进行总结和梳理. 如果遇到相同困惑的朋友也可以看下~
Question 1 结构类型放在.h文件与.c文件的区别
(PS: 是指结构类型的定义, 而非声明--- 具体区别见: http://jingyan.baidu.com/article/020278118e51e01bcd9ce576.html)
情形1 : 将结构类型(struct) 放在.h文件中
头文件 structtst.h
#ifndef _Stest_H_ #define _Stest_H_ int a; int b; struct test { int a; int b; }; #endif
测试主函数
#include<stdio.h> #include "structtst.h" int main() { struct test tst; tst.a=10; tst.b=20; a=30; b=40; printf("tst.a=%d, tst.b=%d\n",tst.a,tst.b); printf("a=%d, b=%d\n",a,b); }
运行结果如下
从而可见: 当将结构类型放在头文件中, 主函数包含该头文件则可以直接试用结构类型(即可以进行声明和定义).
情形2: 将结构类型放在另一个.c文件而非主函数中
头文件 structtst.h
#ifndef _Stest_H_ #define _Stest_H_ int a; int b; struct test; typedef struct test *tst; struct test *GetStruct(); #endif
非主函数的.c文件
#include<stdio.h> #include<stdlib.h> struct test { int a; int b; }; struct test *GetStruct() { struct test *tst; tst=malloc(sizeof(struct test)); tst->a=10; tst->b=20; return tst; }
主函数测试
测试1 :
#include<stdio.h> #include "structtst.h" int main() { struct test t; }
提示错误如下:
测试2:
#include<stdio.h> #include "structtst.h" int main() { tst t; t=GetStruct(); t->a=10; }
提示错误如下:
(PS: 当去掉 t->a=10 这句则正确)
总结: 从上述几种错误可以看出这种方式 将失去对 struct的"主导权", 只能将与 struct内的内容全部在定义其的.c中显示,在返回---即实际权利全都在此.c文件!
(总感觉此处还是存在挺多不正确之处, 发现望指出! 此外,可以参考看下 http://stackoverflow.com/questions/6316987/should-struct-definitions-go-in-h-or-c-file )
Question 2 malloc和free的使用
(此处主要来自: http://www.cnblogs.com/hanyonglu/archive/2011/04/28/2031271.html)
函数原型:
void *malloc(size_t size); ----给函数分配size个字节,返回指向这块内存的指针. 若分配失败,则返回NULL
(ps : malloc 函数返回的是 void * 类型。对于C++,如果你写成:p = malloc (sizeof(int)); 则程序无法通过编译,报错:“不能将 void* 赋值给 int * 类型变量”。所以必须通过 (int *) 来将强制转换。而对于C,没有这个要求,但为了使C程序更方便的移植到C++中来,建议养成强制转换的习惯。)
void free(void *memblock); ---memblock: 释放之前分配的内存块, free 函数解除分配之前通过调用calloc、malloc或者 realloc 分配的存储区 (memblock)。
函数使用的注意事项:
A、申请了内存空间后,必须检查是否分配成功。
B、当不需要再使用申请的内存时,记得释放;释放后应该把指向这块内存的指针指向NULL,防止程序后面不小心使用了它。
C、这两个函数应该是配对。如果申请后不释放就是内存泄露;如果无故释放那就是什么也没有做。释放只能一次,如果释放两次及两次以上会出现错误(释放空指针例外,释放空指针其实也等于啥也没做,所以释放空指针释放多少次都没有问题)。
D、虽然malloc()函数的类型是(void *),任何类型的指针都可以转换成(void *),但是最好还是在前面进行强制类型转换,因为这样可以躲过一些编译器的检查。
几个关键问题
- malloc()到 底从哪里得到了内存空间?
答案是从堆里面获得空间。也就是说函数返回的指针是指向堆里面的一块内存。操作系统中有一个记录空闲内存地址的链表。当操作系统 收到程序的申请时,就会遍历该链表,然后就寻找第一个空间大于所申请空间的堆结点,然后就将该结点从空闲结点链表中删除,并将该结点的空间分配给程序。
- 在使用malloc()分配内存空间后,一定要记得释放内存空间,否则就会出现内存泄漏
- free()到底释放了什么
free()释 放的是指针指向的内存!注意!释放的是内存,不是指针!指针并没有被释 放,指针仍然指向原来的存储空间。指针是一个变量,只有程序结束时才被销毁。释放了内存空间后,原来指向这块空间的指针还是存在!只不过现在指针指向的内 容的垃圾,是未定义的,所以说是垃圾。因此,释放内存后把指针指向NULL,防止指针在后面不小心又被解引用了。
两函数的机制
事实上,仔细看一下free()的函数原型,也许也会发现似乎很神奇,free()函数非常简单,只有一个参数,只要把指向申请空间的指针传递给free()中的参数就可以完成释放工作!这里要追踪到malloc()的申请问题了。申请的时候实际上占用的内存要比申请的大。因为超出的空间是用来记录对这块内存的管理信息。
大多数实现所分配的存储空间比所要求的要稍大一些,额外的空间用来记录管理信息——分配块的长度,指向下一个分配块的指针等等。这就意味着如果写过一个已分配区的尾端,则会改写后一块的管理信息。这种类型的错误是灾难性的,但是因为这种错误不会很快就暴露出来,所以也就很难发现。将指向分配块的指针向后移动也可能会改写本块的管理信息。
malloc()申请的空间实际就是分了两个不同性质的空间。一个就是用来记录管理信息的空间,另外一个就是可用空间了。而用来记录管理信息的实际上是一个结构体。在C语言中,经常用结构来记录信息!下面看看这个结构体的原型:
程序代码
struct mem_control_block { int is_available; //一般来说应该是一个可用空间的首地址,但这里英文单词却显示出空间是否可用的一个标记 int size; //这是实际空间的大小 };
所以,free()就是根据这个结构体的信息来释放malloc()申请的空间!而结构体的两个成员的大小我想应该是操作系统的事了,
下面看看free()的源代码
void free(void *ptr) { struct mem_control_block *free; free = ptr - sizeof(struct mem_control_block); free->is_available = 1; return; }
malloc源码见: http://blog.csdn.net/zhongjiekangping/article/details/6756907