• 深入理解C语言


    在C语言中,指针的重要性不言而喻,但在很多时候指针又被认为是一把双刃剑。一方面,指针是构建数据结构和操作内存的精确而高效的工具。另一方面,它们又很容易误用,从而产生不可预知的软件bug。下面总结一下指针使用的常见错误。


    一、使用未初始化的指针

    这个错误很常见,指针未初始化时,系统会给指针分配个随机地址,示例如下:

    int *p; //或者 int *p = NULL;
    ···
    *p = 10; //错误,指针未初始化
    

    上述程序将值10写到未知的内存位置,如果p指向系统内存空间,这样很可能把系统本来地址里的内容给覆盖了,会导致程序或者系统的崩溃。


    二、没有释放内存

    在堆中开辟内存以后,使用完成必须释放内存,否则会造成内存泄漏,示例如下:

    int *p = (int *)malloc(100);
    ···
    free(p);
    p = NULL;
    

    三、不断修改内存指针变量

    很多时候使用指针开辟了内存空间,然后如果对指针指向进行改变操作,操作完成后直接释放内存,会释放了不该释放的位置;另外程序丢失了对已开辟内存空间的控制,造成内存泄漏,示例如下:

    //这种时候一般会定义两个指向同一个开辟的内存空间的指针变量,一个用于操作,一个用于释放,避免造成内存泄漏
    char *p = (char *)malloc(100);
    strcpy(p, "abcdefg");
    p += 1; //对指针指向进行改变操作
    *p = 'a';
    free(p);
    p = NULL;
    

    四、注意"野指针"

    "野指针"不是NULL指针,是指向“垃圾”内存的指针。人们一般不会错用NULL指针,因为用if语句很容易判断。但是“野指针”是很危险的,if语句对它不起作用。“野指针”的成因主要有两种:

    第一种,指针变量没有初始化。任何指针变量刚被创建时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。示例如下:

    char *p; //错误,未初始化,成为野指针
    

    第二种,指针变量被free或者delete之后,没有置为NULL,让人误以为是个合法的指针。示例如下:

    char *p = (char *)malloc(100);
    ...
    free(p); //错误,没有置为NULL,成为野指针
    

    五、指针参数申请内存的常见错误

    如果函数的参数是一个指针,不要指望用该指针去申请动态内存,示例如下:

    #include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 
      
    void getMemory(char *p, int num) 
    { 
    	p = (char*)malloc(sizeof(char) * num); 
    } 
      
    int main() 
    { 
    	char *pStr = NULL; 
    	pStr = getMemory(pStr, 200); 
    	strcpy(pStr, "hello world!"); //错误,pStr仍然是空指针 
    	printf("%s", pStr); 
    	free(pStr);
        pStr = NULL;
        
    	return 0; 
    } 
    

    上面getMemory(str, 200)并没有使pStr获得期望的内存,pStr依旧是NULL,为什么?

    问题出在getMemory函数中。编译器总是要为函数的每个参数制作临时副本,指针参数p的副本是_p,编译器使_p = p。在本例中,_p申请了新的内存,只是把_p所指的内存地址改变了,但是p丝毫未变,仍然是空指针。事实上,每执行一次getMemory函数就会泄漏一块内存,因为没有用free释放内存。


    指针参数申请内存的两种正确用法
    第一种用法:使用函数返回值来传递动态内存,示例如下:

    #include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 
      
    char* getMemory(char *p, int num) 
    { 
    	p = (char *)malloc(sizeof(char) * num); 
    	return p; 
    } 
      
    int main() 
    { 
    	char *pStr = NULL; 
    	pStr = getMemory(pStr, 200); 
    	strcpy(pStr, "hello world!");
    	printf("%s", pStr); 
    	free(pStr);
        pStr = NULL;
        
    	return 0; 
    } 
    

    这里强调不要用return语句返回指向”栈内存“的指针,因为”栈内存“指针在函数结束时已经被自动回收。


    第二种用法:使用指向指针的指针作为参数来传递动态内存,示例如下:

    #include <stdio.h> 
    #include <string.h> 
    #include <stdlib.h> 
      
    void getMemory(char **p, int num)
    {
        *p = (char *)malloc(sizeof(char) * num);
    }
    
    int main()
    {
        char *pStr = NULL;
        getMemory(&pStr, 200);
        strcpy(pStr, "hello world!");
        printf("%s", pStr);
        free(pStr);
        pStr = NULL;
    
        return 0;
    }
    

    在需要修改指针变量本身的时候,需要使用指向指针的指针作为参数,这也是传值与传地址的差别所在。


    参考:

    深入理解C语言-指针使用的常见错误


  • 相关阅读:
    关于StringBuilder拼成的json格式数据,在转化成string数据类型后,转义符失效
    jQuery 引用地址{包括jquery和google提供的地址}, 节省你不必要的流量
    jQuery的.bind()、.live()和.delegate()之间区别
    使用Jquery Easy UI要导入的js顺序
    babygin
    card
    DecimalFormat用法
    DATEDIFF 函数 [日期和时间]
    IsDirectory( )的用法
    Arrays.asList()函数
  • 原文地址:https://www.cnblogs.com/linuxAndMcu/p/11262784.html
Copyright © 2020-2023  润新知