139

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
itsaboutcode
  • 24,525
  • 45
  • 110
  • 156

15 Answers15

266

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

Neuron
  • 5,141
  • 5
  • 38
  • 59
cmroanirgo
  • 7,297
  • 4
  • 32
  • 38
  • 2
    Actually, the function needs to return a `char *`, as string literals in C are of type `char[]`. They, however, must not be modified in any way, so returning `const char*` is preferred (see https://www.securecoding.cert.org/confluence/x/mwAV). Returning `char *` may be needed if the string will be used in a legacy or external library function which (unfortunately) expects a `char*` as argument, even tough it will only read from it. C++, on the other hand, has string literals of `const char[]` type (and, since C++11, you can also have `std::string` literals). – TManhente Mar 30 '14 at 12:33
  • A point of opinion: I've always detested 'My' in any form of code. It shows lack of thinking about who owns the code and doesn't add any information about what the code does. I've always grilled newbies straight from uni who have this deplorable habit. even 'Some' is oodles better than 'My' – cmroanirgo Jun 18 '14 at 09:46
  • 18
    @cmroanirgo the *my* prefix declares to the reader that the function was created by the user. I find it perfectly reasonable to use in such a context. – quant Jul 30 '14 at 00:10
  • 5
    according to here: http://stackoverflow.com/questions/9970295/life-time-of-string-literal-in-c, you can return string literal – Giorgi Moniava Oct 22 '15 at 22:19
  • 9
    The code marked `fraught with problems` in the "Longevity of data" section is actually perfectly valid. String literals have static lifetimes in C/C++. See the link Giorgi mentions above. – ST0 Oct 27 '15 at 15:34
  • the fundamental issue of c is that a static array cannot be created on the stack at runtime unless you have a static memory pool and your own algorithm for simulating malloc at runtime. This is because an array cannot be created if it does not know at compile time how many bytes it requires. C also has no standard way to allocate from an existing memory pool, forcing people to use dynamic memory where it is not necessary, which is worse in terms of space locality than a static memory pool. worse, c does not allow you to return anonymous structs(that contain size info). – Dmytro Jul 16 '16 at 22:17
  • @Dmitry these issues are not particular to C, since the language can support them but these features are not core C and finding the solutions to these problems means you are likely to find bad/negligent implementations since there are no popular package managers for C to develop any sort of trust system. This means you have to invent your own or do a lot of research to write good code that does things as simple as "return a string from a function", because you can't return a string without committing yourself to a punchcard_t data type that has fixed max size, or creating a trust relationship – Dmytro Jul 16 '16 at 22:20
  • @Dmitry where you trust the scope you are passing the dynamic memory to, to release the memory after they are done. You can also return a local pointer but this creates issues when chaining string operations where local scope expires and you get garbage. Basically, without a local static memory pool, there is no way to return a variable sized string from a function in a way that makes sense, the easiest you can do is pass around a punchcard_t(`typedef struct { char[81] data;} punchcard_t;`) with say, 80 characters maximum(excluding null) that will suit most string returns, but not all. – Dmytro Jul 16 '16 at 22:21
  • @Dmitry tldr: the most common ways to return a string in C are: (1) return a string literal. (2) return a punchcard_t-like structure. (3) return a pointer to dynamic memory and pray to god that it will be freed by the caller(even though it probably won't). (4) return a local pointer, this is ok for instant use, but gets invalidated as soon as you start chaining transformations, so you need to copy it to a local buffer before transforming. (5) invent or find a static memory allocator(lightweight) or garbage collector(heavy-weight) that will manage the memory you are returning to avoid (3). – Dmytro Jul 16 '16 at 22:27
  • I don't understand why this answer is kept as correct, considering that it contains wrong information in its detailed explanation: it's not true that string literals are volatile. String literals have unlimited lifetime while the program runs. Local variables don't, but string literals do. This answer *should* be edited, as it's perfectly safe to return string literals: no crash risk at all, even if this answer says the contrary. – cesss Apr 20 '17 at 14:36
  • @cesss. Yeah, sorry for the delay in fixing it. Many others pointed it out too. I was trying to highlight issues with that 'style' of coding that I'm sure you've encountered oodles of times. Hopefully the intent of my answer is somewhat clearer. That said, knowing what can be done with code, and knowing the best way to code is not always clear, as you know. – cmroanirgo Apr 30 '17 at 05:45
  • 1
    @cmroanirgo Returning string literals is good practice, and good style. It's not "fraught with problems", and it won't crash 9 out of 10 times: It will never crash. Even compilers from the 80s (at least the ones I've used) correctly support the unlimited lifetime of string literals. Note: I'm not sure what you meant about editing the answer: I still see it says it's prone to crashes. – cesss May 06 '17 at 12:12
13

A C string is defined as a pointer to an array of characters.

If you cannot have pointers, by definition you cannot have strings.

Crashworks
  • 40,496
  • 12
  • 101
  • 170
  • 2
    You can pass in an array to a function and then operate on that array: `void foo( char array[], int length)`. Of course, `array` is a pointer under the hood, but it is not "explicitly" a pointer, and it may therefore be more intuitive for somebody learning arrays but who *hasn't quite* learned pointers. – jvriesem Feb 24 '20 at 22:49
13

Note this new function:

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

I defined "array" as static. Otherwise when the function ends, the variable (and the pointer you are returning) gets out of scope. Since that memory is allocated on the stack, and it will get corrupted. The downside of this implementation is that the code is not reentrant and not threadsafe.

Another alternative would be to use malloc to allocate the string in the heap, and then free on the correct locations of your code. This code will be reentrant and threadsafe.

As noted in the comment, this is a very bad practice, since an attacker can then inject code to your application (he/she needs to open the code using GDB, then make a breakpoint and modify the value of a returned variable to overflow and fun just gets started).

It is much more recommended to let the caller handle about memory allocations. See this new example:

char* myFunction(char* output_str, size_t max_len)
{
   const char *str = "my string";
   size_t l = strlen(str);
   if (l+1 > max_len) {
      return NULL;
   }
   strcpy(output_str, str);
   return output_str;
}

Note that the only content which can be modified is the one that the user. Another side effect - this code is now threadsafe, at least from the library point of view. The programmer calling this method should verify that the memory section used is threadsafe.

alcan
  • 31
  • 1
  • 8
elcuco
  • 8,948
  • 9
  • 47
  • 69
  • 2
    This is generally a bad way to go about things. The char* is able to be manipulated by the surrounding code. That is, you can do things like this: strcpy(myFunction(), "A really long string"); and your program will crash due to access violation. – cmroanirgo Jun 18 '14 at 09:44
  • 2
    Something is missing near *"the one that the user"*. – Peter Mortensen Apr 30 '20 at 14:19
8

Your problem is with the return type of the function - it must be:

char *myFunction()

...and then your original formulation will work.

Note that you cannot have C strings without pointers being involved, somewhere along the line.

Also: Turn up your compiler warnings. It should have warned you about that return line converting a char * to char without an explicit cast.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
caf
  • 233,326
  • 40
  • 323
  • 462
  • 2
    I think the signature should const char* since the string is a literal but if I'm not mistaken the compiler will accept this. – Luke Sep 30 '09 at 06:30
5

Based on your newly-added backstory with the question, why not just return an integer from 1 to 12 for the month, and let the main() function use a switch statement or if-else ladder to decide what to print? It's certainly not the best way to go - char* would be - but in the context of a class like this I imagine it's probably the most elegant.

Twisol
  • 2,762
  • 1
  • 17
  • 17
3

Your function return type is a single character (char). You should return a pointer to the first element of the character array. If you can't use pointers, then you are screwed. :(

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
hrnt
  • 9,882
  • 2
  • 31
  • 38
3

You can create the array in the caller, which is the main function, and pass the array to the callee which is your myFunction(). Thus myFunction can fill the string into the array. However, you need to declare myFunction() as

char* myFunction(char * buf, int buf_len){
  strncpy(buf, "my string", buf_len);
  return buf;
}

And in main, myFunction should be called in this way:

char array[51];
memset(array, 0, 51); /* All bytes are set to '\0' */
printf("%s", myFunction(array, 50)); /* The buf_len argument  is 50, not 51. This is to make sure the string in buf is always null-terminated (array[50] is always '\0') */

However, a pointer is still used.

Neuron
  • 5,141
  • 5
  • 38
  • 59
ChainLooper
  • 380
  • 3
  • 7
2

Or how about this one:

void print_month(int month)
{
    switch (month)
    {
        case 0:
            printf("January");
            break;
        case 1:
            printf("february");
            break;
        ...etc...
    }
}

And call that with the month you compute somewhere else.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sebastiaan M
  • 5,775
  • 2
  • 27
  • 28
  • 1
    +1 not what OP asked but this is probably what the assignment expect you to do, since he can't use pointers. – Vitim.us Apr 13 '13 at 22:54
  • Even printf uses pointers. A pointer is like a knife -- essential for living and working, but you have to hold it by the handle and use the sharp side to cut with or you are gonna have a bad time. The unfortunate placing of spaces in the function definition is a brain bug for many a new C programmer. char * func( char * s); char *func( char *s); char* func * char* s); are all the same but all look different, and to compound confusion, * is also the de-reference operator for variables that are pointers. – Chris Reid Mar 19 '16 at 08:09
1

A char is only a single one-byte character. It can't store the string of characters, nor is it a pointer (which you apparently cannot have). Therefore you cannot solve your problem without using pointers (which char[] is syntactic sugar for).

Nick Bedford
  • 4,365
  • 30
  • 36
1

If you really can't use pointers, do something like this:

char get_string_char(int index)
{
    static char array[] = "my string";
    return array[index];
}

int main()
{
    for (int i = 0; i < 9; ++i)
        printf("%c", get_string_char(i));
    printf("\n");
    return 0;
}

The magic number 9 is awful, and this is not an example of good programming. But you get the point. Note that pointers and arrays are the same thing (kind of), so this is a bit cheating.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sebastiaan M
  • 5,775
  • 2
  • 27
  • 28
  • Usually if you need to implement such solutions to homework problems, then your preliminary assumptions are wrong. – hrnt Sep 30 '09 at 11:11
1

Well, in your code you are trying to return a String (in C which is nothing but a null-terminated array of characters), but the return type of your function is char which is causing all the trouble for you. Instead you should write it this way:

const char* myFunction()
{

    return "My String";

}

And it's always good to qualify your type with const while assigning literals in C to pointers as literals in C aren't modifiable.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Cheshar
  • 571
  • 1
  • 7
  • 21
1

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.

#include <stdio.h>
#include <stdlib.h>

char *myfunc(){
    char *myvar = (char *)malloc(20);
    printf("Plese enter some text \n");
    fgets(myvar, 20, stdin);
    return myvar;
}
int main(){
    printf("You entered: %s", myfunc());
}
mustafa candan
  • 567
  • 5
  • 16
0

Your function prototype states your function will return a char. Thus, you can't return a string in your function.

user224579
  • 427
  • 3
  • 14
0
char* myFunction()
{
    return "My String";
}

In C, string literals are arrays with the static constant memory class, so returning a pointer to this array is safe. More details are in Stack Overflow question "Life-time" of a string literal in C

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
0

Return string from function

#include <stdio.h>

const char* greet() {
  return "Hello";
}

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