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

举报
ReCclay 发表于 2022/02/22 00:18:33 2022/02/22
【摘要】 写在前面的话 emm,,C语言字符串和指针两大精华,得之得C天下。 其实有一个问题,原来一直困扰着自己,只是自己总是选择忽略,今天又暴露了出来,必须得去解决一下了。 另外关于字符串的另一...

写在前面的话

emm,,C语言字符串和指针两大精华,得之得C天下。

其实有一个问题,原来一直困扰着自己,只是自己总是选择忽略,今天又暴露了出来,必须得去解决一下了。

另外关于字符串的另一些博文:

1、字符数组和字符指针的比较学习

2、字符串那些事。


问题

Q:如何在一个函数返回字符数组(或者字符串)呢?

解决方法

参考了一下网友的,大概也就四种方法吧:

下面给出四种返回字符串的方法:

1、 将字符串指针作为函数参数传入,并返回该指针。

2、 使用malloc函数动态分配内存,注意在主调函数中释放。

3、 返回一个静态局部变量。

4、 使用全局变量。

当然各有利弊,就拿一个例子来具体学习下吧。

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

char* MyString()
{
    char str[12];
    strcpy(str, "王sir");
    return str;

}

int main()
{
    char *x;
    x = MyString();
    printf("%s", x);
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

CB编译后 。。。

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

意即返回局部变量的地址,而我们知道局部变量当函数调用完毕后就释放了。你也就根本不知道这个内存会是什么了。

怎么办呢?

办法一:

很容易想到的,我把它直接定义成static,不就相当于全局变量了嘛!这样这块内存地址就不会随着函数调用完毕而消灭了。

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

char* MyString()
{
    static char str[12];
    strcpy(str, "王sir");
    return str;

}

int main()
{
    char *x;
    x = MyString();
    printf("%s", x);
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

注意:

需要注意,不要修改返回的这个字符串,由于是共享地址,对它的修改会反应到每个调用者的。

可以这样:

戳这里,了解更详细const关键字。

const char* MyString()
{
    static char str[12];
    strcpy(str, "王sir");
    return str;

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

简单吧,简单归简单,但是问题也随之而来了。

由于采用了静态局部变量(位于静态区,程序结束时由系统进行释放),这就导致,如果多次调用这个函数,下一次调用会将上一次调用的结果覆盖掉。

C语言中的库函数,tmpnam()函数、getenv()函数等应该都是采用的这种方法,这也就是为什么,使用这样的函数的时候应该立即将返回结果拷贝一份的原因

这俩函数是啥?

别急,我也没用过,百度一波。

看例程吧。。

char *tmpnam(char *str)

返回值: 一个指向 C 字符串的指针,该字符串存储了临时文件名。如果 str 是一个空指针,则该指针指向一个内部缓冲区,缓冲区在下一次调用函数时被覆盖。
如果 str 不是一个空指针,则返回 str。如果函数未能成功创建可用的文件名,则返回一个空指针。

#include <stdio.h>

int main()
{
   char buffer[L_tmpnam];
   char *ptr;


   tmpnam(buffer);
   printf("临时名称 1: %s\n", buffer);

   ptr = tmpnam(NULL);
   printf("临时名称 2: %s\n", ptr);

   return(0);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

再来看下:

char *getenv(const char *name)

返回值 该函数返回一个以 null 结尾的字符串,该字符串为被请求环境变量的值。如果该环境变量不存在,则返回 NULL。

同样,直接看例程吧。

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

int main ()
{
   printf("PATH : %s\n", getenv("PATH"));
   printf("HOME : %s\n", getenv("HOME"));
   printf("ROOT : %s\n", getenv("ROOT"));

   return(0);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

方法二:

既然局部变量相当于全局变量了,那我们直接定义全局变量当然也是可以的!

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

char str[12];

char* MyString()
{
    strcpy(str, "王sir");
    return str;

}

int main()
{
    char *x;
    x = MyString();
    printf("%s", x);
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

方法三:

将其作为字符指针传入,特别注意如果此时想让其作为字符指针为参数传入函数,那么它实参本身必须为字符数组

言外之意字符指针(指向字符数组的指针)仅仅为一个存储地址的地方,而字符数组才是存东西的地方。


错误的示范

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


void MyString(char *str)
{
    strcpy(str, "王sir");
}

int main()
{
    char *x;
    MyString(x);
    printf("%s", x);
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

正确的示范

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


void MyString(char *str)
{
    strcpy(str, "王sir");
}

int main()
{
    char x[10];
    MyString(x);
    printf("%s", x);
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这种缺点,也可直接从主函数中看到,对应的x,即字符数组的内存要足够。
防止意外的溢出,可以这样。指定长度

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

void MyString(char *str, int len)
{
    strncpy(str, "王sir", len-1);
    str[len-1] = '\0';
}

int main()
{
    char x[10];
    MyString(x, 10);
    printf("%s", x);
    return 0;
}
  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

方法四

思路也很容易想到,还是想让那个地址保存住。除了静态变量或者全局变量外。我们还可以利用malloc 函数进行在堆中分配内存,但是要特别注意,堆要即时释放!

关于内存分配函数再来回忆一波。。

void *malloc(unsigned size)

eg: 关于sizeof和strlen的区别戳这里。

int p = (int )malloc(n*sizeof(int))
申请对应该机器可存放n个int的内存空间。

对了,还有个colloc函数,函数原型为:

void *calloc(unsigned n, unsigned size);

它和malloc函数的区别还有,calloc可以自己置0,但是malloc需要借助memset或者循环手动置0。

memset(a, 0, sizeof(a))


直接对应都是字符指针也无妨。。

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

char* MyString()
{
    char *str;
    str = (char *)malloc(10);
    strcpy(str, "王sir");
    return str;

}

int main()
{
    char *x;
    x = MyString();
    printf("%s", x);
    free(x);
    return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

参考:
1、四种返回字符串数组的方法(1)
2、四种返回字符串数组的方法(2)

文章来源: recclay.blog.csdn.net,作者:ReCclay,版权归原作者所有,如需转载,请联系作者。

原文链接:recclay.blog.csdn.net/article/details/78946179

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。