我试图从函数返回一个C字符串,但它不起作用.这是我的密码.

char myFunction()
{
    return "My String";
}

main中,我这样称呼它:

int main()
{
  printf("%s", myFunction());
}

我还try 了其他一些myFunction美元的方法,但它们都不起作用.例如:

char myFunction()
{
  char array[] = "my string";
  return array;
}

注意:我不允许使用指针!

关于这个问题的小背景:

有一个功能是找出现在是哪一个月.例如,如果它是1,那么它返回1月,等等.

所以当它要打印的时候,它是这样做的:printf("Month: %s",calculateMonth(month));.现在的问题是如何从calculateMonth函数返回该字符串.

推荐答案

您的函数签名需要是:

const char * myFunction()
{
    return "my String";
}

背景资料:

这对C&;C++,但是更多的讨论应该是有序的.

在C(& C++)中,字符串只是一个以零字节结尾的字节数组,因此,术语"字符串零"被用来表示字符串的这种特殊味道.还有其他种类的字符串,但在C(&;C++)中,这种风格本质上是由语言本身理解的.其他语言(Java、Pascal等)使用不同的方法来理解"my string".

如果你使用Windows API(C++),你会经常看到函数参数,比如:"LPCSTR lpszName"."sz"部分代表了"string zero"的概念:一个带有空(/zero)终止符的字节array.

澄清:

为了这个"介绍",我交替使用"字节"和"字符",因为这样更容易学习.请注意,还有其他方法(宽字符和多字节字符系统(mbcs))用于处理国际字符.UTF-8是mbcs的一个示例.为了介绍,我悄悄地"跳过"了这一切.

记忆:

这意味着像"my string"这样的字符串实际上使用9+1(=10!)字节.当您最终开始动态分配字符串时,了解这一点很重要.

所以,如果没有这个"终止零",就没有字符串.内存中有一个字符数组(也称为缓冲区).

数据的生命周期 :

该函数的使用方法如下:

const char * myFunction()
{
    return "my String";
}

int main()
{
    const char* szSomeString = myFunction(); // Fraught with problems
    printf("%s", szSomeString);
}

...通常会给您带来随机的未处理的异常/段错误等,特别是"以后".

简而言之,虽然我的答案是正确的--如果你这样使用程序,十有八九会导致程序崩溃,特别是如果你认为这样做是"好的做法".简而言之:通常不是这样的.

例如,想象future 某个时候,字符串现在需要以某种方式进行操作.通常,程序员会"走捷径",并(try )编写如下代码:

const char * myFunction(const char* name)
{
    char szBuffer[255];
    snprintf(szBuffer, sizeof(szBuffer), "Hi %s", name);
    return szBuffer;
}

也就是说,您的程序将崩溃,因为在调用main()中的printf()时,编译器(可能/可能没有)已经释放了szBuffer使用的内存.(你的编译器也应该提前警告你这些问题.)

有两种方法可以返回不那么容易呕吐的字符串.

  1. 返回存在一段时间的缓冲区(静态或动态分配).在C++中,使用"帮助类"(例如,std::string)来处理数据的生命周期 (这需要改变函数的返回值),或者
  2. 将缓冲区传递给填充信息的函数.

请注意,在C语言中,如果不使用指针,就不可能使用字符串.正如我所展示的,它们是同义词.即使在C++中使用模板类,后台也总是使用缓冲区(即指针).

所以,为了更好地回答(现在修改的问题).(肯定有各种"其他答案"可以提供.)

更安全的答案:

Example 1, using statically allocated strings:

const char* calculateMonth(int month)
{
    static char* months[] = {"Jan", "Feb", "Mar" .... };
    static char badFood[] = "Unknown";
    if (month < 1 || month > 12)
        return badFood; // Choose whatever is appropriate for bad input. Crashing is never appropriate however.
    else
        return months[month-1];
}

int main()
{
    printf("%s", calculateMonth(2)); // Prints "Feb"
}

在这里,static所做的(许多程序员不喜欢这种类型的"分配")是将字符串放入程序的数据段.也就是说,它是永久分配的.

如果您转向C++,您将使用类似的策略:

class Foo
{
    char _someData[12];
public:
    const char* someFunction() const
    { // The final 'const' is to let the compiler know that nothing is changed in the class when this function is called.
        return _someData;
    }
}

... 但是,如果您编写的代码是供自己使用的(而不是要与他人共享的库的一部分),那么使用helper类(例如std::string)可能会更容易.

100

这是传递字符串的更"简单"的方式.返回的数据不受呼叫方的操纵.也就是说,示例1很容易被调用方滥用,并使您面临应用程序故障.这样,它更安全(尽管使用了更多的代码行):

void calculateMonth(int month, char* pszMonth, int buffersize)
{
    const char* months[] = {"Jan", "Feb", "Mar" .... }; // Allocated dynamically during the function call. (Can be inefficient with a bad compiler)
    if (!pszMonth || buffersize<1)
        return; // Bad input. Let junk deal with junk data.
    if (month<1 || month>12)
    {
        *pszMonth = '\0'; // Return an 'empty' string
        // OR: strncpy(pszMonth, "Bad Month", buffersize-1);
    }
    else
    {
        strncpy(pszMonth, months[month-1], buffersize-1);
    }
    pszMonth[buffersize-1] = '\0'; // Ensure a valid terminating zero! Many people forget this!
}

int main()
{
    char month[16]; // 16 bytes allocated here on the stack.
    calculateMonth(3, month, sizeof(month));
    printf("%s", month); // Prints "Mar"
}

第二种方法更好的原因有很多,特别是如果您正在编写供其他人使用的库(您不需要锁定到特定的分配/释放方案,第三方不能 destruct 您的代码,您也不需要链接到特定的内存管理库),但是像所有代码一样,您最喜欢什么取决于您.出于这个原因,大多数人 Select 例如1,直到他们被烧了很多次,以至于他们拒绝再这样写了;)

免责声明:

几年前我退休了,现在我的C有点Rust 了.这个演示代码应该全部用C编译(虽然对于任何C++编译器都是可以的).

C++相关问答推荐

C中的ATONE会扰乱SEN/CLUTE GMS应用程序中的其他字符串

C strlen on char array

变量>;-1如何在C中准确求值?

在没有动态内存分配的情况下,用C语言最快地将各种数组复制到单个较大的数组中

如何在C客户端应用程序的ClientHello消息中添加自定义扩展?

C是否用0填充多维数组的其余部分?

使用C时,Windows CMD中的argc参数是否包含重定向命令?

为什么GDB/MI进程的FIFO循环中有read()阻塞

双指针指向常量双指针的指针类型赋值不兼容

对于C中给定数组中的每个查询,如何正确编码以输出给定索引范围(1到N)中所有数字的总和?

防止C++中递归函数使用堆栈内存

对于STM32微控制器,全局偏移表.get和.Got.plt必须为零初始化

当我将偏移量更改为任何非零值时,C中的mmap共享内存出现无效参数错误

在我的第一个C语言中观察到的错误';你好世界';程序

在C中交换字符串和数组的通用交换函数

指向返回 struct 成员的指针,安全吗?

C Makefile - 如何避免重复提及文件名

Linux memcpy 限制关键字语法

为什么需要struct in_addr

返回指向函数内声明的复合文字的指针是否安全,还是应该使用 malloc?