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函数中返回字符数组


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

查看所有标签

猜你喜欢:

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

从零开始做运营

从零开始做运营

张亮 / 中信出版社 / 2015-11-1 / 49.00元

运营是什么?怎样做运营?产品和运营是什么关系?我是否适合从事互联网运营?为什么我做的运营活动收效甚微? 在互联网大热的今天,互联网运营成为一个越来越重要的岗位,事关网站、产品的发展与存亡。很多年轻人带着对互联网的热情投身到这个行业,却发现自己对这个行业所知甚少,对互联网运营更加陌生,甚至有一些有志于从事互联网运营的人,因为对运营缺乏了解而难以确定自己的职业发展方向。本书的出发点就在于此,它将......一起来看看 《从零开始做运营》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

在线进制转换器
在线进制转换器

各进制数互转换器

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

正则表达式在线测试