关于C语言中返回局部指针变量

前言

写这篇文章,是因为同学在leetcode上遇到了这样一个错误:
- 题目:Two Sum
- 代码如下:

int* twoSum(int* nums, int numsSize, int target)
{
    int i,j;
    int res[2];                                 /* 加上static之后正常运行 */
    for (i=0; i<numsSize; i++) {
        for (j=i; j<numsSize; j++) {
            if (nums[i]+nums[j]==target) {
                res[0]=i;
                res[1]=j;
                break;
            } else {
                continue;
            }
        }
    }
    return res;
}

- 运行时出现错误:

load of null pointer of type 'const int'

- Google之后发现,在声明res[2]的时候加上static就可以正常运行。于是在《The C Programming Language》(P70,4.6 静态变量)找到了相关内容:

用static限定外部变量与函数,可以将其后声明的对象的作用域限定为被编译源文件的剩余部分。该外部变量/函数除了对该所在的文件可见外,其他文件都无法访问。
用static声明内部变量,则该变量是某个特定函数的局部变量,只能在该函数中使用。但它与自动变量不同的是,不管其所在函数是否被调用,它一直存在,而不像自动变量那样,随着所在函数的被调用和退出而存在和消失。换句话说,static类型的内部变量是一种只能在某个特定函数中使用但一直占据存储空间的变量。

分析上面的代码,函数返回了一个int类型的指针,但是报错却说是一个空指针。猜想是int res[2];的声明导致res是一个自动变量的数组指针,在退出该函数之后,res指针指向的内存被覆盖,所以导致出错。使用static进行声明,可以保证res[2]不会因为函数的退出而消失。下面进行验证。

验证

  • 参考资料

    关于C语言中返回局部变量和局部指针变量

  • 平台和工具

    • Windows 10, Code::Blocks-16.01(mingw)
  • 测试代码

    
    #include <stdio.h>
    
    char *test1(void)
    {
        /*
         * 编译时出现warning,运行时打印乱码。
         * char b[10] 是局部变量,其存放在栈上,在函数执行完成就会被释放。
         * 而返回它存放的地址,此时已经是可能是个非法地址。
         * 运行时打印乱码,验证了b[10]的内存被释放。
         */
        char b[10] = "abcde";
        return b;                     // warning: function returns address of local variable [-Wreturn-local-addr]|
    }
    char *test1_ver2(void)
    {
        /*
         * 正确运行。
         * 定义static char b[10]; 将其存放在静态存储区,只有在程序运行结束后才会被系统回收。
         * 即使退出该函数,b[]数组存放的静态存储区始终存在,所以,我们再对其进行访问,不会出现错误。
         */
        static char b[10] = "abcde";
        return b;
    }
    char *test2(void)
    {
        /*
         * 可以运行,但打印出错。
         * c[10]和*pStr均为自动变量,保存在栈中;函数返回时,c[]数组和pStr指针的内存空间被释放
         * 所以,在外部访问c[]数组时,指向的内存空间无效。
         */
        char c[10] = "abcde";
        char *pStr = c;
        return pStr;
    }
    char *test3(void)
    {
        /*
         * 正确运行。
         * 指针c保存在栈中,但是"abcdef"字符串保存在常量区,其内存空间直到程序运行结束才会被释放。
         * 所以,返回的地址是一个实际存在的有效地址。
         */
        char *c = "abcdef";
        return c;
    }
    int main()
    {
        char *p_test1, *p_test1_ver2, *p_test2, *p_test3;
        p_test1 = test1();
        p_test1_ver2 = test1_ver2();
        p_test2 = test2();
        p_test3 = test3();
    
        printf("test1:%s\n", p_test1);
        printf("test1_ver2:%s\n", p_test1_ver2);
        printf("test2:%s\n", p_test2);
        printf("test3:%s\n", p_test3);
    
        return 0;
    }
  • 输出结果1:

    test1:[w骾      A
    test1_ver2:abcde
    test2:`
    test3:abcdef
  • 输出结果2:

    test1:[w詡?
    test1_ver2:abcde
    test2:`
    test3:abcdef
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页