C语言陷阱---指针的误用

引言

     在 C 语言学习中,最大的难点就是对指针的理解和使用上。指针与内存息息相关,所以要理解指针的用法,也必须对所在平台系统的内存布局有所了解,你至少能够区分堆和栈吧(当然,此处的堆栈,可不是数据结构所指的堆栈)。指针就像一把双刃剑,用好了能写出令人惊叹的高效简洁的代码,用不好,就等着程序出现各种莫名奇妙的问题吧^_^

    注:本文如无特别说明,均在 Ubuntu 14.10 64位中文系统, gcc 4.9.1 环境下编译执行。


使用未初始化的指针

1. 示范代码

#include
#include

int main()
{
    char *ptr;
    strcpy(ptr, "hello");
    printf("%s", ptr);
    return 0;
}    

2. 错误分析

若不用-Wall 选项,gcc 编译器不会给出任何提示就能够生成可执行程序;若使用 gcc -Wall 选项编译上述代码,编译器会给出警告信息如下所示:

use_uninital_pointer.c: In function ‘main’:
use_uninital_pointer.c:7:5: warning: ‘ptr’ is used uninitialized in this function [-Wuninitialized]
     strcpy(ptr, "hello");
     ^
在 Ubuntu 机器上执行,出现以下信息: 段错误 (核心已转储)。 

指针操作内存地址越界

1. 示范代码

#include
#include

int main()
{
    int *p = NULL;
  
    p = (int *)malloc(5 * sizeof(int));
    if(NULL != p)
    {
        for(int i = 0; i <= 6; i++)
        {
           p[i] = i;
           printf("p[%d]=%d\t", i, p[i]);
        }
        printf("\n");
        free(p);
    }
    return 0;
}


2. 错误分析

编译示范代码并执行,结果如下:

thomas@thomas-host:~/workspace/BlogSample$ gcc -Wall -std=c99 pointer_over_bound.c 
thomas@thomas-host:~/workspace/BlogSample$ ./a.out 
p[0]=0	p[1]=1	p[2]=2	p[3]=3	p[4]=4	p[5]=5	p[6]=6	
*** Error in `./a.out': free(): invalid next size (fast): 0x0000000001e20010 ***
已放弃 (核心已转储)
错误原因在于只给指针 p 申请了 5 个 整型空间大小,但使用了 7  个,导致释放内存时崩溃。(注:在我的环境,使用 6  个空间大小,程序运行没有什么异常,此处为了说明问题,特意增加了2个越界)

对于该例子,不同的环境,可能有差异,可以对比在Windows 平台 Dev C++ 编译运行的结果,请查看 循环条件中边界错误导致越界。

动态分配的内存未释放

1. 示范代码

#include
#include
#include

int main()
{
    char *src = "Hello";
    char *dst = malloc(sizeof(strlen(src) + 1));
    if(NULL == dst)
    {
        return -1;
    }
    strcpy(dst, src);
    printf("dst=%s\n",dst);
    return 0;
}

2. 错误分析

在示范代码中,动态申请了 dst 的内存空间,但是没有调用 free 进行释放。此类错误比较常见,特别上在复杂的项目中,需要不断申请和释放内存,而且又有各种异常处理和返回操作时。对于长时间运行的服务器程序来说,内存没有释放,是造成内存泄漏,导致程序崩溃的罪魁祸首。


继续使用已释放的内存

1. 示范代码

#include
#include
#include

int main()
{
    char *src = "Hello";
    char *dst = malloc(sizeof(strlen(src) + 1));
    if(NULL == dst)
    {
        return -1;
    }
    strcpy(dst, src);
    free(dst);
    printf("dst=%s\n",dst);
    return 0;
}

2. 错误分析

以上代码,输出结果如下:

dst=
是因为 dst 已经被释放了,在 printf 函数中又使用了。在不同的编译环境下,上述结果可能不相同,有的系统可能仍然能够输出 dst=Hello 字样。这正是指针操作让人麻痹的地方。明明程序在自己的环境中运行得好好的,为什么一发布到客户或在测试人员机器上就不正常了呢?

总结


你可能感兴趣的:(C/C++)