Как вернуть string из функции c
Перейти к содержимому

Как вернуть string из функции c

  • автор:

How to return a string from a C function

In one of my C programs, I had the task to return a string from a function:

The tricky thing is defining the return value type.

Strings in C are arrays of char elements, so we can’t really return a string — we must return a pointer to the first element of the string.

This is why we need to use const char* :

Here’s an example working program:

If you prefer to assign the result to a variable, you can invoke the function like this:

We can write the pointer operator * also in this ways:

All forms are perfectly valid.

Note the use of const , because from the function I’m returning a string literal, a string defined in double quotes, which is a constant.

Note that you can’t modify a string literal in C.

Another thing to keep in mind is that you can’t return a string defined as a local variable from a C function, because the variable will be automatically destroyed (released) when the function finished execution, and as such it will not be available, if you for example try do do:

you’ll have a warning, and some jibberish, like this:

Notice the B��Z> K���⏎ line at the end, which indicates that the memory that was first taken by the string now has been cleared and there’s other random data in that memory. So we don’t get the original string back.

Changing myName() to

makes the program work fine.

The reason is that variables are allocated on the stack, by default. But declaring a pointer, the value the pointers points to is allocated on the heap, and the heap is not cleared when the function ends.

Return a String From a Function in C++

Return a String From a Function in C++

This article explains several methods of how you can return a string from a function in C++.

Use the std::string func() Notation to Return String From Function in C++

Return by the value is the preferred method for returning string objects from functions. Since the std::string class has the move constructor, returning even the long strings by value is efficient. If an object has a move constructor, it’s said to be characterized with move-semantics. Move-semantics imply that the object is not copied to a different location on function return, thus, providing faster function execution time.

Use the std::string &func() Notation to Return String From Function

This method uses return by reference notation, which can be an alternative approach to this problem. Even though return by reference is the most efficient way to return large structures or classes, it would not impose extra overhead compared to the previous method in this case. Take note that you shouldn’t replace a local variable declared in the function by a reference; this leads to a dangling reference.

Use the char *func() Notation to Return String From Function

Alternatively, we can use char * to return a string object from a function. Remember that the std::string class stores characters as a continuous array. Thus, we can return a pointer to the first char element of that array by calling the built-in data() method. However, make sure you don’t to use a similar c_str() method when returning null-terminated character array of std::string object, as it replaces the const pointer to the first char element.

Как вернуть массив строк C++?

Учи матчасть: массив из функции вернуть нельзя. Можно вернуть указатель на массив или структуру содержащую массив.

Слева в этом выражении стоит массив из нуля элементов. Справа — указатель на string.
Что ты хотел этим выражением сказать?

  • Facebook
  • Вконтакте
  • Twitter

ВНИМАНИЕ: У вас есть пара тонких мест.
РАЗ. не забудьте, что строковые литералы в Си — это нуль-терминированные строки, и «\0» по факту будет пустой строкой. Строку из одного нулевого символа можно загнать в string — например, конструктором string(begin, end) или s += ‘\0’, но не конструктором string(const char*).
ДВА. Этот static будет инициализирован при первом вызове. Второй вызов вернёт тот же массив.
ТРИ. Строчку лучше передавать как string *func(const string& s) <>

К делу. Массив — это довольно сложный объект, и возникает вопрос: кто этим массивом будет владеть после того, как он покинет пределы функции?
1. Владеет система времени выполнения. Это отлично ответил Роман, дам только ключевую строчку.
string* arr = func(exp);
НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ: если массив используется в чьих-то «конских» конструкторах-деструкторах статических объектов (из-за отсутствия модулей Си++ не позволяет установить на уровне языка порядок создания/уничтожения статических объектов).

2. Владеет какой-то объект.

НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ: ну, это уж разбирайтесь сами с этим объектом, сколько он будет жить и насколько долго он будет держать массив. В данном случае каждый новый вызов уничтожает старый массив. (Код корявый, потому что последний массив не уничтожается.)

3. Владеет тот, кто вызывает. Лучше для таких целей использовать какой-нибудь std::vector.

Returning a C string from a function

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

In main I am calling it like this:

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

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.

Peter Mortensen's user avatar

15 Answers 15

Your function signature needs to be:

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:

. 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:

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:

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:

. 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):

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).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *