如何将调用函数作为strcpy中的第二个字符串?

问题描述

我需要从 main 调用一个函数来确定一个字符串值。但是,据我所知,字符串不能采用 string_name = call_function() 形式。字符串的赋值必须是 strcpy(str1,str2) 的形式对吗?所以我想知道我在用 strcpy 作为变量名的 str1 做错了什么,而 str2 是另一个函数的返回字符串值。

到目前为止,这就是我所拥有的。

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

char *get_name(int num);

char *get_name(int num) {
    char real_name[30];
    
    if (num == 1)
        strcpy(real_name,"Jake Peralta");
    
    return real_name;
}

void main() {
    char name[30];
    int num;
    
    num = 1;
    
    strcpy(name,*get_name(num));
    printf("%s",name);
}

它没有在我的输出屏幕上打印任何内容

我尝试过的:

  • get_name(num) 不使用指针(仍然不起作用)

p/s:这不是实际的代码。这只是我想要做一个例子,实际代码更长,我已经确定这部分是错误的来源。

解决方法

您是对的,字符串不能通过 return 语句作为数组返回。当您传递或返回数组时,仅使用指向其第一个元素的指针。因此,函数 get_name() 返回一个指向本地定义的数组的指针,该数组具有自动存储(又名在堆栈上)。这是不正确的,因为这个数组一旦超出范围就会被丢弃,即:当函数返回时。

get_name() 可以通过多种方式为其调用者提供名称:

  • 您可以传递目标数组及其长度:并让函数在数组中填充名称,小心避免写到数组末尾之外,但要确保它有一个空终止符:

     char *get_name(char *dest,size_t size,int num) {
         if (num == 1) {
             snprintf(dest,size,"Jake Peralta");
         } else {
             snprintf(dest,"John Doe");
         }
         // return the destination pointer for convenience.
         return dest;
     }
    
     int main() {
         char name[30];
         int num = 1;
         get_name(name,sizeof name,num);
         printf("%s\n",name);
         return 0;
     }
    
  • 您可以在 get_name() 中分配内存并返回指向您复制字符串的已分配数组的指针。当不再使用该对象时,调用者有责任使用 free() 释放该对象。

     char *get_name(int num) {
         if (num == 1) {
             return strdup("Jake Peralta");
         } else {
             return strdup("John Doe");
         }
     }
    
     int main() {
         int num = 1;
         char *name = get_name(num);
         printf("%s\n",name);
         free(name);
         return 0;
     }
    
  • 您可以返回一个常量字符串,但只有在编译时所有名称都已知的情况下才能这样做。

     const char *get_name(int num) {
         if (num == 1) {
             "Jake Peralta";
         } else {
             "John Doe";
         }
     }
    
     int main() {
         int num = 1;
         const char *name = get_name(num);
         printf("%s\n",name);
         return 0;
     }
    
,

您正在从 real_name 方法返回 get_name 的地址,该地址将在函数返回后超出范围。而是在堆上分配字符串的内存并返回其地址。此外,调用者需要释放在堆上分配的字符串内存以避免任何内存泄漏。

,

就像您说的,“但是,据我所知,字符串不能采用 string_name = call_function() 形式。”要了解这背后的逻辑,只需查看您的 get_name() 函数:

char *get_name(int num)
{
    char real_name[30];
    
    if (num==1)
        strcpy(real_name,"Jake Peralta");
    
    return real_name;
}

这里,您尝试返回 real_name 的起始地址,但是当 real_name 超出范围时(在这种情况下,当函数返回时)会被销毁。我认为有两种方法可以解决此问题。一种是添加应该保存返回值的字符串作为参数。在您的情况下,它将是:

void get_name(int num,char *dest)
{
    char real_name[30];
    
    if (num==1)
    {
        strcpy(real_name,"Jake Peralta");
        strcpy(dest,real_name);
    }
}

或者,现在完全避免使用 real_name 以缩短函数:

void get_name(int num,char *dest)
{
    if (num==1)
        strcpy(dest,"Jake Peralta");
}

另一种方式是在堆上分配返回值,但我不建议这样做;您必须跟踪每个分配的字符串并最终释放所有字符串。不过,在您的情况下,情况如下所示:

char *get_name(int num,char *dest)
{
    char *real_name = calloc(30,sizeof(char)); // Using calloc to avoid returning an uninitialized string if num is not 1
    if (num==1)
        strcpy(real_name,"Jake Peralta";
    return real_name;
}

顺便说一下,我将您的 strcpy 保留在这里,但可能希望将来避免使用它,因为它会导致缓冲区溢出。 Here's a post with useful answers as to why it's bad。事实上,即使 strncpy 也不是完全安全的(请参阅 here(感谢 @chqrlie 提供链接))。 @chqrlie 在他自己的回答中使用 snprintf 提供了一种干净且安全的替代方案,我建议您使用它。