从函数返回C字符串 [英] Returning a C string from a function

查看:50
本文介绍了从函数返回C字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  char myFunction(){返回我的字符串";} 

main 中,我这样称呼它:

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

我还尝试了 myFunction 的其他方法,但是它们不起作用.例如:

  char myFunction(){char array [] =我的字符串";返回数组;} 

注意:不允许使用指针!

有关此问题的背景知识很少

有一个功能可以确定是哪个月.例如,如果为1,则返回一月,依此类推.

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

解决方案

您的函数签名必须为:

  const char * myFunction(){返回我的字符串";} 

背景:

这对C&C ++,但应该再进行一些讨论.

< p>在C(就此而言为& C ++)中,字符串只是以零字节结尾的字节数组-因此,术语字符串-零"表示字符串.用于表示字符串的这种特殊风格.还有其他种类的字符串,但是在C(& C ++)中,这种味道是语言本身固有地理解的.其他语言(Java,Pascal等)使用不同的方法来理解我的字符串" .

如果您曾经使用Windows API(C ++),则会经常看到类似"LPCSTR lpszName"的功能参数."sz"部分表示字符串零"的概念:带有空(/零)终止符的字节数组.

说明:

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

内存:

这意味着像"my string" 这样的字符串实际上使用9 + 1(= 10!)个字节.重要的是要知道何时最终可以动态分配字符串.

因此,没有这个终止零",您就没有字符串.您有一个字符数组(也称为缓冲区)在内存中徘徊.

数据寿命:

此功能的使用方式:

  const char * myFunction(){返回我的字符串";}int main(){const char * szSomeString = myFunction();//充满问题printf(%s",szSomeString);} 

...通常会使您陷入随机的,未处理的异常/段故障等,尤其是在路上".

简而言之,尽管我的回答是正确的-如果以这种方式使用它,最终会导致程序崩溃(十分之九),特别是如果您认为以这种方式进行操作是好的习惯"时,该程序将崩溃.简而言之:通常不是.

例如,想象一下将来的某个时间,现在需要以某种方式来操作字符串.通常,编码人员会走简单的路"并(尝试)编写如下代码:

  const char * myFunction(const char *名称){char szBuffer [255];snprintf(szBuffer,sizeof(szBuffer),"Hi%s",名称);返回szBuffer;} 

也就是说,您的程序将崩溃,因为在中的 printf()之前,编译器已经(可能会/可能不会)释放了 szBuffer 所使用的内存.> main()被调用.(您的编译器也应事先警告您此类问题.)

有两种方法可以返回不容易发声的字符串.

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

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

因此,为了更好地回答(现在已修改的问题).(肯定会提供各种各样的其他答案".)

更安全的答案:

示例1,使用静态分配的字符串:

  const char * calculateMonth(int month){static char * months [] = {"Jan","Feb","Mar"....};static char badFood [] =未知";如果(月< 1 ||月> 12)返回badFood;//选择适合错误输入的任何内容.但是,崩溃永远是不合适的.别的返回月份[month-1];}int main(){printf(%s",calculateMonth(2));//打印"Feb"} 

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

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

  Foo类{char _someData [12];上市:const char * someFunction()const{//最后的'const'是让编译器知道在调用此函数时类中没有任何更改.返回_someData;}} 

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

示例2,使用调用方定义的缓冲区:

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

  void computeMonth(int month,char * pszMonth,int buffersize){const char * months [] = {"Jan","Feb","Mar"....};//在函数调用期间动态分配.(如果编译器不正确,效率可能会降低)如果(!pszMonth || buffersize< 1)返回;//输入错误.让垃圾处理垃圾数据.如果(month< 1 || month&12;){* pszMonth ='\ 0';//返回一个空"字符串//或:strncpy(pszMonth,"Bad Month",buffersize-1);}别的{strncpy(pszMonth,months [month-1],buffersize-1);}pszMonth [buffersize-1] ='\ 0';//确保有效的终止零!许多人忘记了这一点!}int main(){字符月份[16];//在堆栈中分配16个字节.computeMonth(3,month,sizeof(month));printf(%s",月);//打印"Mar"} 

第二种方法更好的原因有很多,特别是如果您正在编写供他人使用的库(无需锁定特定的分配/取消分配方案,则第三方不会破坏)您的代码,而不必链接到特定的内存管理库),但是像所有代码一样,它取决于您最喜欢的代码.出于这个原因,大多数人会选择例如1直到被烧很多次,以至于拒绝再用这种方式写了;)

免责声明:

几年前我退休了,现在我的C有点生锈了.该演示代码应全部使用C正确编译(尽管对于任何C ++编译器都可以).

I am trying to return a C string from a function, but it's not working. Here is my code.

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

In main I am calling it like this:

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

I have also tried some other ways for myFunction, but they are not working. For example:

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

Note: I am not allowed to use pointers!

Little background on this problem:

There is function which is finding out which month it is. For example, if it's 1 then it returns January, etc.

So when it's going to print, it's doing it like this: printf("Month: %s",calculateMonth(month));. Now the problem is how to return that string from the calculateMonth function.

解决方案

Your function signature needs to be:

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

Background:

It's so fundamental to C & C++, but little more discussion should be in order.

In C (& C++ for that matter), a string is just an array of bytes terminated with a zero byte - hence the term "string-zero" is used to represent this particular flavour of string. There are other kinds of strings, but in C (& C++), this flavour is inherently understood by the language itself. Other languages (Java, Pascal, etc.) use different methodologies to understand "my string".

If you ever use the Windows API (which is in C++), you'll see quite regularly function parameters like: "LPCSTR lpszName". The 'sz' part represents this notion of 'string-zero': an array of bytes with a null (/zero) terminator.

Clarification:

For the sake of this 'intro', I use the word 'bytes' and 'characters' interchangeably, because it's easier to learn this way. Be aware that there are other methods (wide-characters, and multi-byte character systems (mbcs)) that are used to cope with international characters. UTF-8 is an example of an mbcs. For the sake of intro, I quietly 'skip over' all of this.

Memory:

This means that a string like "my string" actually uses 9+1 (=10!) bytes. This is important to know when you finally get around to allocating strings dynamically.

So, without this 'terminating zero', you don't have a string. You have an array of characters (also called a buffer) hanging around in memory.

Longevity of data:

The use of the function this way:

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

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

... will generally land you with random unhandled-exceptions/segment faults and the like, especially 'down the road'.

In short, although my answer is correct - 9 times out of 10 you'll end up with a program that crashes if you use it that way, especially if you think it's 'good practice' to do it that way. In short: It's generally not.

For example, imagine some time in the future, the string now needs to be manipulated in some way. Generally, a coder will 'take the easy path' and (try to) write code like this:

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

That is, your program will crash because the compiler (may/may not) have released the memory used by szBuffer by the time the printf() in main() is called. (Your compiler should also warn you of such problems beforehand.)

There are two ways to return strings that won't barf so readily.

  1. returning buffers (static or dynamically allocated) that live for a while. In C++ use 'helper classes' (for example, std::string) to handle the longevity of data (which requires changing the function's return value), or
  2. pass a buffer to the function that gets filled in with information.

Note that it is impossible to use strings without using pointers in C. As I have shown, they are synonymous. Even in C++ with template classes, there are always buffers (that is, pointers) being used in the background.

So, to better answer the (now modified question). (There are sure to be a variety of 'other answers' that can be provided.)

Safer Answers:

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

What the static does here (many programmers do not like this type of 'allocation') is that the strings get put into the data segment of the program. That is, it's permanently allocated.

If you move over to C++ you'll use similar strategies:

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

... but it's probably easier to use helper classes, such as std::string, if you're writing the code for your own use (and not part of a library to be shared with others).

Example 2, using caller-defined buffers:

This is the more 'foolproof' way of passing strings around. The data returned isn't subject to manipulation by the calling party. That is, example 1 can easily be abused by a calling party and expose you to application faults. This way, it's much safer (albeit uses more lines of code):

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

There are lots of reasons why the second method is better, particularly if you're writing a library to be used by others (you don't need to lock into a particular allocation/deallocation scheme, third parties can't break your code, and you don't need to link to a specific memory management library), but like all code, it's up to you on what you like best. For that reason, most people opt for example 1 until they've been burnt so many times that they refuse to write it that way anymore ;)

Disclaimer:

I retired several years back and my C is a bit rusty now. This demo code should all compile properly with C (it is OK for any C++ compiler though).

这篇关于从函数返回C字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆