【问题标题】:returning string from a function but prints null, what is the reason?从函数返回字符串但打印 null,这是什么原因?
【发布时间】:2020-11-15 17:07:00
【问题描述】:

我试图从 str 函数返回一个字符串,但它打印 (null)

#include<stdio.h>
char* str()
{
    char hi[10] = "return this";
    return hi;
}

void main()
{
    printf("%s", str());

}

【问题讨论】:

  • 由于 histr 的范围内,返回它的地址超出范围是没有意义的。

标签: arrays c string


【解决方案1】:

读取static variablesglobal variables 以访问函数外的变量

你的代码有溢出,阅读buffer overflow in c

另请阅读What should main() return in C and C++?

#include<stdio.h>
char* str()
{
    static char hi[] = "return this";
    return hi;
}

int main()
{
    printf("%s", str());
    return 0;
}

【讨论】:

  • 初始化程序太大不会导致溢出,因为它是在编译时检查的,这就是它打印(null)的原因——尽管它仍然是未定义的行为。如果您缩短初始化程序,它可能(并且在这种简单的情况下很可能)似乎工作,但它仍然是错误的。
  • 不确定,但这仍然不是正确的做法,对吧?
  • 没错。我描述的行为是我在 gdbonline (GCC).. YMMV 凭经验确定的。一个实现不佳的编译器很可能会溢出缓冲区。
【解决方案2】:

在 GCC 中,至少您的代码在编译时会出现以下警告:

main.c:12:19: warning: initializer-string for array of chars is too long                                                                        
main.c:13:12: warning: function returns address of local variable [-Wreturn-local-addr]  

这或多或少是对您问题的直接回答。如果您没有收到这些警告,请考虑切换您正在使用的编译器,对于 GCC,我建议至少 -Wall -Werror - 这将输出最有用的警告而不是迂腐,并且使这些警告错误因此将阻止成功编译,直到您修复他们。

您正在返回一个指向本地自动变量的指针,该变量在函数返回后不再位于范围内,因此结果未定义。您还尝试使用您保留的更多字符来初始化一个数组。

编译器在这里所​​做的是给定了无效的初始化程序,它将hi的地址设置为null,并且printf通过打印(null)来处理空指针。这是特定于您的编译器和 C 库的行为 - 在其他情况下可能会发生不同的情况。更阴险的是,如果您的初始化程序不是无效的(通过更短),它很可能 似乎 可以工作,而您可能从未问过这个问题,但它仍然是不正确的,并且在更复杂的代码中可能会在某些时候导致可观察到的错误行为。

在这种特殊情况下,您可以执行以下任何操作:

const char* str()
{
    static const char* hi = "return this";
    return hi;
}
const char* str()
{
    static const char hi[] = "return this";
    return hi;
}
char* str( char* str, int maxlen )
{
    str[maxlen] = '\0' ;
    return strncpy( str, "return this", maxlen - 1 ) ;
}

void main()
{
    char* buffer[32] ;
    printf("%s", str(buffer, sizeof(buffer));
}

最合适的解决方案(以上绝不是详尽的)取决于您实际想要做什么,因为每个解决方案在语义上都不同,而且这个功能本身几乎不实用。它需要一个具体的真实示例来提供最佳建议。

【讨论】:

    【解决方案3】:

    问题在于字符数组的范围。

    解决这个问题的办法是让那个变量的地址对调用函数可见!

    即 最简单的解决方案之一是在 str() 函数的 hi 变量的声明部分中使用以下行。 IE。 static char hi[10] = "return th";

    在声明中。 这样您就不需要更改此程序中的任何内容,但在整个程序中,此变量将在整个执行过程中可见/可访问。

    #include"stdio.h"
    
    char* str() {
        static char hi[10] = "return th";
        return hi; 
    }
    
    int main() {
        printf("%s", str());
        return 0;
    }
    

    【讨论】:

    • 您的解决方案以何种方式使变量“可见/可访问”贯穿整个项目?一个变量有scopelifetime,通过声明一个本地的static它有一个lifetime的程序持续时间,但它不是比非静态变量更明显,因为它具有相同的范围
    • 您应该编辑答案以添加解释性代码,而不是将其添加到 cmets。评论不是答案的一部分,当然也不适合发布代码。
    【解决方案4】:
    #include<stdio.h>
    #include<stdlib.h>
    char* str(){
        //malloc is used to allocate memory
        char *hi=(char*)malloc(sizeof(char)*20);
        char ch[]="return this\0";
        for(int i=0;i<sizeof(ch);i++)
        hi[i]=ch[i];
        return hi;
    } 
    int main(){
        printf("%s", str());
        return 0;
    }
    

    您可以找到有关mallocsizeof 运算符的更多信息。

    【讨论】:

    • 您的 hi 变量范围被限制为 str function 。所以当执行来自 str 函数时,堆栈被清除,因此分配给 hi 的内存也被清除,因为它给出了分段错误。
    • 哎呀。只是将一个问题换成另一个问题(内存泄漏)。此外,sizeof(char) 的定义为 1,因此 sizeof(char)*20 与此处的 20 相比没有任何优势。
    • 您对自己答案的评论是答案的一部分,应该出现在答案中。只是在没有解释的情况下抛出代码并不是问题的真正答案,即使它是问题的解决方案。
    猜你喜欢
    • 2023-04-05
    • 1970-01-01
    • 2016-05-11
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    • 2013-01-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多