添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
酷酷的茴香  ·  mysql ...·  4 月前    · 
不羁的眼镜  ·  yml中的特殊字符-掘金·  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
#undef strcpy
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>
#undef strcpy
#ifndef STRCPY
# define STRCPY 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编译错误截图如下:
在这里插入图片描述

Clang编译错误如下:

Array type 'char [14]' is not assignable

可以考虑使用 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函数中返回字符数组,CSDN同步发布。转载请注明出处,谢谢!内容简介在阅读本篇文章之前,建议大家看一下下面2篇文章:不见得你会计算C字符串长度双宿双飞的 malloc 和 free这篇文章主要分享两个点:1、为什么作为局部变量的字符数组不能直接返回,而字符指针却可以?2、当字符数组是局部变量的时候,函数如何返回它?3、字符数组(char [])和字符指针(char...
函数返回字符串方法字符串指针作为函数形参传入,并返回指针使用malloc函数动态分配(注意内存释放)返回一个静态局部变量 static使用全局变量strcpy函数用法 字符串指针作为函数形参传入,并返回指针 #include <stdio.h> #include <string.h> #include <stdlib.h> char * fun(char *p) char *eg="STM32"; strcpy(p,eg); return
C++指向数组指针函数参数 一维数组名可以作为函数参数传递,多维数组名也 可作函数参数传递。 C++用字符数组存放一个字符串在C++可以用多种方法访问一个字符串,第一种字符数组:#include<iostream>//预处理 using namespace std;//命名空间 int main()//主函数 char str[]="关注:C语言入门到精通";
C 语言不允许返回一个完整的数组作为函数的参数。但是,可以通过指定不带索引的数组名来返回一个指向数组指针。我们将在下一章讲解有关指针的知识,可以先跳过本章,等了解了 C 指针的概念之后,再来学习本章的内容。 如果想要从函数返回一个一维数组,必须声明一个返回指针函数,如下: int * myFunction() 另外,C 不支持在函数返回局部变量的地址,除非定义局部变量为static变量。 现在,让我们...
问题出在如此想了一下C语言如何实现返回一个字符串数组,答之:没有这种功能,但是吧,还是有办法实现的。那就是指向数组指针解释char **p 这个p就是指向数组指针,它指向一个数组的起始地址. 想要引用里面的数组时,直接使用p[i] 即可。我们知道C语言里面的各种数组,本质上都是指针,并且函数其实也是不能把数组当作参数的,实际上都是把数组的地址传进去了,实际上就是指向数组地址的指针。说了这么多
C语言自定义函数如何返回数组 使用 C 语言,在 main() 函数调用了一个自定义的函数,想要从函数获取其运行产生的字符串,直接返回数组是实现不了的,最起码也要返回数组的地址。但是在自定义函数创建数组后,该数组本身是一个局部变量,当该自定义函数的生命周期结束后,局部变量也就被回收了,即使返回了一个代表数组的地址,但实际上其指代的内容可能已经发生了变化。 有三种方法可以实现自定义函数成功返回数组: 1、将数组定义为全局变量; 2、使用malloc在堆区开辟动态空间; 3、在调用函数时传入数组地址。 char *GetString(void) char str[] = "hello"; //开辟一个能连续存放6个字符的数组,将“hello”字符串常量拷贝到数组 return str; //返回数组的起始地址 简单几行代码,一眼就可以看出:这是一个C语言返回数组...
文章目录一、字符指针可以返回,而作为局部变量的字符数组不能直接返回的原因二、如何返回局部变量的字符数组1、使用 static2、使用 malloc3、全局变量4、返回形参指针变量三、字符数组与字符指针的区别相同点不同点小结四、字符数组和字符指针的转换char [] 转 char *char*转char[] 参考博客:c函数返回字符串数组 一、字符指针可以返回,而作为局部变量的字符数组不能直接返回...