C函数中返回字符数组

栏目: 服务器 · Linux · 发布时间: 5年前

内容简介:在阅读本篇文章之前,建议大家看一下下面2篇文章:这篇文章主要分享三个点:1、为什么作为局部变量的字符数组不能直接返回,而字符指针却可以?

在阅读本篇文章之前,建议大家看一下下面2篇文章:

这篇文章主要分享三个点:

1、为什么作为局部变量的字符数组不能直接返回,而字符指针却可以?

2、当字符数组是局部变量的时候,函数如何返回它?

3、字符数组(char [])和字符指针(char *)如何互转?

局部变量的字符数组

在C中如果我们直接返回字符数组,编译会直接报警告。如下示例:

char * fork_user_name()
{
    char name[] = "veryitman";
    return name;
}

在Xcode中编译警告信息是这样的:

Address of stack memory associated with local variable 'name' returned

Linux 上面GCC编译显示警告是这样的:

warning: function returns address of local variable [-Wreturn-local-addr]

无论哪种警告信息,基本意思都是告诉我们不应该返回一个局部变量 name 的地址(函数内部的变量在栈内存上)。

如果我们修改一下代码,将 char 改为指针变量 char * ,示例如下:

char * fork_user_name2()
{
    char *name = "veryitman";
    return name;
}

无论是Linux的GCC还是Xcode的Clang编译器都不会报出警告。

首先我们要知道,常量是放在数据段里面的。

这里比较特殊,局部变量 name 保存在栈中,但是字符串 veryitman 的值是一个常量,保存在常量区。即便函数返回了,数据段里面的常量数据也还不会消亡,它会直到程序结束才会消失,其内存空间直到程序运行结束才会被释放。 所以,返回的地址是一个实际存在的有效地址。

char * fork_user_name()
{
    char name[] = "veryitman";
    return name;
}

char * fork_user_name2()
{
    char *name = "veryitman";
    return name;
}

int main()
{
    printf("fork_user_name: %s\n", fork_user_name());
    printf("fork_user_name2: %s\n", fork_user_name2());
    
    return 0;
}

用GCC编译、运行后的打印结果,如下:

fork_user_name: (null)
fork_user_name2: veryitman

总之,在函数中的局部变量只要是返回类似 int[]char[]long[] 地址的,都是不正确的做法。

一切皆有可能

下面例子是不正确的,如下:

char * v_string()
{
    char rest[10] = {'\0'};
    return rest;
}

1、使用 static

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

所以使用static修饰一下,就没有问题了。示例如下:

char * v_string()
{
    static char rest[10] = {'\0'};
    return rest;
}

2、使用 malloc

这种方式可以解决这个问题,是因为使用 malloc 分配的内存是在堆上而不是在栈内存上面。但是要记得将其在调用方使用 free 释放申请的内存空间,否则容易造成内存泄漏问题。

具体可以看看 双宿双飞的 malloc 和 free ) 这篇文章。

char * v_string()
{
    char *p = (char *)malloc(10 * sizeof(char));
    p = "\0";
    return p;
}

3、全局变量

这个很好理解。全局变量在程序真个生命周期中都是有效的,所以使用全局变量也可以解决类似问题。

但是这种方案就会让这个封装的方法不够内聚,因为它依赖了全局变量。

char g_rest[100];
char * v_string()
{
    strcpy(g_rest, "verytiamn");
    return g_rest;
}

4、返回形参指针变量

在Linux Kernel(内核源码版本5.0.7)中,函数 strcpy 的实现如下:

#ifndef__HAVE_ARCH_STRCPY
/**
* strcpy - Copy a %NUL terminated string
* @dest: Where to copy the string to
* @src: Where to copy the string from
*/
#undefstrcpy
char *strcpy(char *dest, const char *src)
{
    char *tmp = dest;

    while ((*dest++ = *src++) != '\0')
        /* nothing */;
    return tmp;
}
EXPORT_SYMBOL(strcpy);
#endif

参考内核实现,我们可以修改一下自己的代码,示例如下:

char * v_string(char *s1, char *s2)
{
    char *tmp = s1;
    // 省略...
    return tmp;
}

这里补充另外一个知识点,函数 strcpy 在glibc和Linux Kernel中实现不一样。

在glibc的新版中(2.29版本),本质是调用了函数 memcpy , 实现如下:

#include<stddef.h>
#include<string.h>

#undefstrcpy

#ifndefSTRCPY
#defineSTRCPY strcpy
#endif

/* Copy SRC to DEST. */
char * STRCPY(char *dest, const char *src)
{
  return memcpy (dest, src, strlen (src) + 1);
}
libc_hidden_builtin_def (strcpy)

包括 strncpy 在glibc和Linux Kernel中实现也不一样,有兴趣的可以去看看源码。

字符数组和字符指针的互转

字符数组转字符指针即 char [] 转 char *

这种情况下,可以直接进行赋值,示例如下:

int main()
{
    char c_str_array[] = "veryitman.com";
    char *p_str;
    p_str = c_str_array;
    printf("p_str: %s\n", p_str);
    return 0;
}

字符指针转字符数组即 char * 转 char []

是不是也可以直接进行赋值呢?撸段代码看看,如下:

int main()
{
    char c_str_array[] = "veryitman.com";
    char *p_str = "veryitman.com";
    c_str_array = p_str;
    printf("c_str_array: %s\n", c_str_array);
    return 0;
}

很遗憾,编译报错,GCC编译错误截图如下:

C函数中返回字符数组

Clang编译错误如下:

可以考虑使用 strncpy 来实现,示例代码如下:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>

int main()
{
    char c_str_array[] = "veryitman.com";
    char *p_str = "veryitman.com";
    strncpy(c_str_array, p_str, strlen(p_str));
    printf("c_str_array: %s\n", c_str_array);
    return 0
}

时间可以改变一切,但你得做点什么!

C函数中返回字符数组


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

浪潮之巅(下册)

浪潮之巅(下册)

吴军 / 人民邮电出版社 / 2013-6 / 45.00元

《浪潮之巅(第2版)(下册)》不是一本科技产业发展历史集,而是在这个数字时代,一本IT人非读不可,而非IT人也应该阅读的作品。一个企业的发展与崛起,绝非只是空有领导强人即可达成。任何的决策、同期的商业环境,都在都影响着企业的兴衰。《浪潮之巅》不只是一本历史书,除了讲述科技顶尖企业的发展规律,对于华尔街如何左右科技公司,以及金融风暴对科技产业的冲击,也多有着墨。此外,《浪潮之巅》也着力讲述很多尚在普......一起来看看 《浪潮之巅(下册)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试