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

How to have a call function as the second string in strcpy?

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

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

#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);
}

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

我尝试过的:

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

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

正如您所说,“但是,据我所知,字符串不能采用 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;
}

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

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");
}

另一种方法是在堆上分配return值,但我不推荐这样做;您将不得不跟踪每个分配的字符串并最终释放所有它们。不过,在您的情况下,情况如下:

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. In fact, even strncpy isn't fully safe (See here(归功于提供 link 的@chqrlie)。 @chqrlie 在他自己的回答中使用 snprintf 提供了一种干净安全的替代方法,我建议您使用它。

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

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

  • 您可以传递目标数组及其长度:并让函数填充数组中的名称,小心避免写入超出数组末尾但确保它有空终止符:

     char *get_name(char *dest, size_t size, int num) {
         if (num == 1) {
             snprintf(dest, size, "Jake Peralta");
         } else {
             snprintf(dest, size, "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() 和 return 中分配一个指向您复制字符串的分配数组的指针。调用者有责任在不再使用时使用 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;
     }
    
  • 您可以 return 常量字符串,但只有在编译时已知所有名称时才能这样做。

     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;
     }