C函数中返回字符数组

C语言系列之C语言如何返回字符串数组 问题出在如此想了一下C语言如何实现返回一个字符串数组,答之:没有这种功能,但是吧,还是有办法实现的。那就是指向数组的指针解释char **p 这个p就是指向数组的指针,它指向一个数组的起始地址. 想要引用里面的数组时,直接使用p[i] 即可。我们知道C语言里面的各种数组,本质上都是指针,并且函数其实也是不能把数组当作参数的,实际上都是把数组的地址传进去了,实际上就是指向数组地址的指针。说了这么多 阅读详情

原文 C函数中返回字符数组,优快云同步发布。

转载请注明出处,谢谢!


内容简介

在阅读本篇文章之前,建议大家看一下下面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语言fgets和fputs函数的用法详解(初稿) 和函数 每次读写"一个字符",速度较慢实际开发中往往是每次读写一个字符串或者一个数据块,这样能明显提高效率。用来 从中"读取一个字符串",并保存到"字符数组"中它的用法为:为 字符数组为要读取的"字符数目"为"文件指针"返回值:读取"成功"时返回""(即str)读取"失败"时返回"如果时 文件内部指针 已经,那么将也返回NULL。注意,会在自动加'\0', n个字符也包括'\0'。 阅读详情

相关推荐

间充质干细胞衰老机制与抗衰老干预策略研究

干细胞技术在再生医学领域具有广阔应用前景,其中间充质干细胞(MSCs)因其多向分化潜能和免疫调节特性备受关注。细胞衰老是影响干细胞治疗效果的共性难题,表现为增殖能力下降、端粒缩短等特征。通过表观遗传学分析发现,衰老MSCs存在DNA甲基化异常和组蛋白修饰改变;线粒体功能障碍导致ATP产量锐减,ROS累积显著增加。针对这些机制,研究者开发了包括小分子化合物筛选、CRISPR基因编辑和三维培养优化在内的多种干预策略。这些技术在组织修复、抗衰老治疗等应用场景中展现出重要价值,例如可提升心肌梗死修复效率2.3倍,缩

weixin_33502772的博客 230

返回字符串函数的方法总结

返回字符函数。

悟已往之不谏 知来者之可追 5016

Qt Coordinate System

Qt 坐标系统Qt 坐标系统 数学基础 Qt坐标系统 视口 平移变换 缩放变换 setWindow 旋转 总结数学基础 矩阵与线性变换坐标系变换Qt坐标系统 视口和OpenGL一样,视口确定了画面在窗口(QWidget)中显示的区域,Qt的绘图坐标会完全映射到视口(View port)上,就像图示一样。默认情况下,窗口和视口是重合的,视口的大小覆盖了整个窗口。和OpenGL一样,Qt的QPa

unclerunning的博客 1151

返回字符串数组_【建议收藏】你一定会用到的数组的31个方法

点击文字关注我哦~数组常用操作01. pop作用:删除数组的最后一项 返回值:删除的那一项是否改变原有数组: 是var arr = [1,2,3];var ret = arr.pop();console.log(ret); //3 删除的最后一项console.log(arr) // [1,2] 改变了原有数组02. push作用:添加元素到数组的末尾返回值:数组的长度是否改变原有数...

weixin_42667269的博客 1244

双内核架构 Xenomai 4 安装教程

双内核 Xenomai 4 安装指南

^_^ 4471

DDR Study - LPDDR5 Power-Up and Initialization Sequence

本文深入解析LPDDR5内存的上电初始化流程,涵盖电源斜坡、复位信号释放和初始化训练等关键阶段。通过实际案例分享,详细探讨了电源轨时序、RESET信号处理、ZQ校准和CA总线训练等核心技术要点,帮助硬件工程师规避常见设计陷阱,确保DDR内存稳定运行。

weixin_42523792的博客 304

C语言如何在函数中正确返回字符串指针或字符串数组

函数返回字符串的四种方法:https://blog.youkuaiyun.com/luna_zhan/article/details/80433196 例如,定义一个函数,要求该函数能够返回一个指向字符串“I love C.”的指针并能在主程序中正确得到该字符串的内容。 对于初学者来说,当看到这个题目时,感觉并不难做到,可能很容易的写出下面形式的代码: 代码中定义了一个函数getString1...

小跑 5369

嵌入式开发实战:LWIP中PPP协议配置全流程(含CHAP认证避坑指南)

本文是一份嵌入式开发实战指南,详细解析了如何在STM32平台上配置LWIP协议栈中的PPP协议,实现从串口到IP网络的完整连接。内容涵盖工程搭建、源码整合、关键配置、串口驱动绑定、状态管理以及CHAP认证等核心流程,并重点提供了CHAP认证失败的排查与避坑指南,帮助开发者高效打通嵌入式设备的网络连接。

plant的博客 464

c函数中返回字符串数组、char[]和char*的区别与转换(详细)

文章目录一、字符指针可以返回,而作为局部变量的字符数组不能直接返回的原因二、如何返回局部变量的字符数组1、使用 static2、使用 malloc3、全局变量4、返回形参指针变量三、字符数组与字符指针的区别相同点不同点小结四、字符数组和字符指针的转换char [] 转 char *char*转char[] 参考博客:c函数中返回字符串数组 一、字符指针可以返回,而作为局部变量的字符数组不能直接返回...

锵锵锵锵蒋的博客 1万+

DoubletFinder实战:如何优化参数提升scRNA-seq双细胞识别准确率?

本文深入探讨了如何通过优化DoubletFinder参数提升scRNA-seq双细胞识别准确率。详细解析了pK和nExp参数的影响机制,提供了系统化的参数优化流程和多样本整合策略,并结合真实数据集演示了验证方法与高级应用场景,帮助研究人员获得更可靠的分析结果。

weixin_28523493的博客 340

图神经网络学习笔记-点云数据处理(专题七)

本教程解释了如何利用图神经网络(Graph Neural Networks,GNNs)来处理和训练点云数据。尽管点云默认情况下不具有图结构,但我们可以利用 PyG 的转换工具,将其转化为适合 PyG 所提供的全套 GNN 模型的形式。关键思想是从点云数据中创建一个,通过 GNN 的消息传递机制,从中学习有意义的局部几何结构。这些点的表示可以被用于例如点云分类或分割等任务。

351

C语言编程>第二十二周 ② 请补充fun函数,该函数的功能是:返回字符数组中指定字符的个数,指定字符从键盘输入。

例题:请补充fun函数,该函数的功能是:返回字符数组中指定字符的个数,指定字符从键盘输入。 注意:请勿改动主函数main和其它函数中的任何内容,仅在fun函数的横线上填写所需的若干表达式或语句。 代码如下: #include<stdio.h> #define N 100 int fun(char s[],char ch) { int i=0,sum=0; while(s[i]) { if(s[i]==ch) sum++; i++; } return sum; } main

朽木自雕i的博客 1万+

V90伺服 EPOS模式下回原(详细配置+SCL源代码)

/ 输出上限 100.0%rSetPoint : Real;// 设置目标值工程量。// 通道转换参考值。Td : Real;

RXXW_Dor的博客 2666

C语言中函数返回的字符数组为null——函数中的局部字符数组

今天在刷题时,碰到这样一个问题,我定义的函数要求返回的是字符串,我在函数中定义了一个字符数组来表示,但是运行时发现函数的返回值为空。 解决方法: 方法1:将字符数组定义为全局变量 方法2:通过malloc申请 ...

weixin_44003177的博客 1216

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

字符数组做函数返回值_c语言函数指针的理解与使用

1.函数指针的定义  顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:A看看上面三个表达式分别是什么意思?C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。B) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指...

weixin_39863631的博客 475

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

leetcode刷题-c语言如何在函数中返回字符数组

题目: 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀,返回空字符串 “”。 代码: char* longestCommonPrefix(char** strs, int strsSize) { int n=strlen(strs[0]); static char a[n]; int i; int j; for(...

ykz5555的博客 1267

关于C语言中strcmp()函数比较两个字符数组返回随机值问题

【代码】关于C语言中strcmp()函数比较两个字符数组返回随机值问题。

weixin_58888381的博客 840

C语言 字符数组/多维数组/函数/作用域

函数如果要使用,首先需要先定义函数,然后调用即可返回值类型名 函数名([参数列表]){函数体/代码块return;函数名([参数列表]);

嵌入式心学修行者,以代码为器,以良知为核。探索嵌入式开发中的“知行合一”,在编译、调试、部署中事上磨练致心中之光,铸可靠之器。 701

C语言atoi函数以“字符数组指针+序号”为参数时的返回情况

测试代码: #include <stdio.h> #include <string.h> using namespace std; int main() { char s[] = "12345"; printf("%d\n", atoi(s)); printf("%d\n", atoi(s+1)); printf("%d\n", atoi(s+2)); pr...

Zen_Ivan的博客 578

09 03 指针作为函数返回值

09 03 指针作为函数返回值 02 整数数组 字符数组 字符串 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> void print(int* a, int len) { for (int i = 0; i < len; i++) { printf("%d ", a[i]); } } void print2(char

weixin_39538253的博客 140

返回函数值-字符串和指针的问题

#include "stdafx.h" #include "stdio.h" char *string() { char pString[] = "abcedigfh"; return pString; } int _tmain(int argc,

tianmo2010的专栏 1412

函数及二维字符数组的补充

字符串初始化:*{}不可省略//字符串的全部初始化//字符串的部分初始化,剩余元素使用\0填充//省略第一维度,默认是实际的行数单字符的初始化//单字符的全部初始化。

qq_57106106的博客 1298

第十七天 C语言 Day17:字符指针与字符串(字符数组/字符指针两种实现)· 字符串作函数参数(四种组合)· 指针函数(返回最大元素/字符串拼接/查询成绩)· 函数指针(回调函数/函数指针数组)

指针收官第 17天,讲清两个高频混淆点。先拆字符串的两种实现:字符数组存在栈上、内容可改但数组名是常量;字符指针指向 .rodata 只读常量、改内容就段错误,只能重新指向。再讲字符串作函数参数的四种组合,核心就一句——数组传参退化成指针。接着是两个最容易写错的概念:指针函数(返回指针的函数)和函数指针(指向函数的指针),配返回最大元素地址、malloc 拼接字符串、查询学生成绩三个案例,以及回调函数、函数指针数组做简易计算器两个应用。文末用「括号里先解释谁」

2302_79608792的博客 151

C语言获取linux shell命令返回值

C语言获取linux shell命令返回值 C语言执行linux shell命令,对于没有返回结果的,可直接使用system()函数,对于有返回结果的,可以用popen命令,对其封装后,可以获取相应的返回信息,封装函数如下: int SystemRtn(const char* Cmd, char* pbyRtnStr) { FILE *fp; int rc = 0; char result_buf[256]; int nOnceLen = 0; int nTotalLen = 0; int i

仰天大笑出门去 2065

c语言将字符型数组作为函数的返回值_8.4 C++字符数组存放字符串 | 字符指针变量...

C++指向数组的指针作函数参数 一维数组名可以作为函数参数传递,多维数组名也 可作函数参数传递。 C++用字符数组存放一个字符串在C++中可以用多种方法访问一个字符串,第一种字符数组:#include<iostream>//预处理 using namespace std;//命名空间 int main()//主函数 { char str[]="关注:C语言入门到精通"; c...

weixin_30954879的博客 1289

C 语言 实现 字符串 分割 函数(返回"二维字符数组",及分割后的字符数组的长度)...

这段时间重拾C语言. 之前只是在大学时草草的学习了一年时间.当然与大部分同学一样.90%以上都还给了老师. 现在只是依稀得记得好像似乎大概学习过~~ 为什么要写这个字符串分割的实现呢. 主要也是对这段时间学习的一个总结. 觉得自带的strtok 方法实现得不够方便 .用惯了C# 还是希望他可以直接将 分割后的字串返回. 其中也练习了几个知识点:结构体,指针,malloc ,释放内存...

weixin_30776863的博客 265
上一篇: 你会计算C字符串长度吗?
下一篇: 微服务: 步步为营
veryitman
博客等级 码龄16年 472粉丝 310原创
评论 7
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值