链表所遇问题

这个板块只要针对个人所遇到的一些问题进行总结和梳理.   如果遇到相同困惑的朋友也可以看下~


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

 

posted @ 2015-04-16 10:44  Nooooooo  阅读(165)  评论(0编辑  收藏  举报