1

I would like to do something like that :

#include <stdio.h>

char * myfunction(char * in);
void myfunction2(char * in, const char ** content);

int main(){
    char * name="aName";
    char * result = myfunction(name);
    return 0;
}

char * myfunction(char * in) {
    const char *test = NULL;
    myfunction2(in, &test);
    return test; // I would like to return the value of test
}

void myfunction2(char * in, const char ** content) {
    char input[1024];
    //do some stuff to fill input
    *content = input;
}

But I'm not able to do it, some weird char are printed instead sometimes...

Thank you for your reply, I understand it well now, but I'm stuck on another side of my problem. I didn't write precisely my use case, so I edited it to be complete.

2
  • What is printed? Also, what compiler are you using? It works fine for me on Linux using gcc. Commented Feb 17, 2014 at 23:48
  • 2
    put prototype before main. Commented Feb 17, 2014 at 23:52

3 Answers 3

3

The most glaring things wrong in this code are:

  1. Implicit declaration of myfunction as int myfunction();
  2. Incorrect const-ness of your pointers.
  3. No return value provided for main()

Implicit declaration of myfunction as int myfunction();

This is easy enough to solve, and your compiler should be barking loudly at you when this happens. As a legacy feature of C, when a function call is encountered where no formal declaration, either by prototype or definition, is known, the function is assumed to return int and accept a variable number of parameters. Therefore in main() your call is assumed to be to a function that looks like this:

int myfunction();

Later when the real myfunction is encountered, at a minimum your compiler should scream at you with warning about how the declaration doesn't match the expected type (because by this time it thinks it is int myfunction()). Even then, however, the call should still go through, but it is terrible practice to rely on this. Properly prototype your functions before use.


Incorrect data types for all your pointers.

The string literal in your function is not bound to local array space. It is a read-only data buffer sitting in a read-only segment somewhere in your program's data blocks. The correct declaration is this:

const char *test = "mytest";

but that has the ripple effect of requiring changes to the rest of this code, which you'll see in a moment.


No return value provided for main()

Be definitive in your conclusion of main(). Apparently C99 allows you to skip this and implementation is supposed to return 0 for you. Don't give them that joy; seize it yourself.


Addressing all of the above...

#include <stdio.h>

void myfunction(const char** in);

int main()
{
    const char *result = NULL;
    myfunction(&result);
    printf("in main() %p : %s\n", result, result);
    return 0;
}

void myfunction(const char** in) 
{
    const char* test = "mytest";
    printf("in myfunction() %p : %s\n", test, test);
    *in = test;
}

Output (varies by implementation)

in main() 0x8048580 : mytest
in myfunction() 0x8048580 : mytest

See it live.

Sign up to request clarification or add additional context in comments.

8 Comments

Remember that C99 defines that if main() falls 'off the bottom' without an explicit return, it is equivalent to return 0; — a mistake (IMNSHO) that was copied from C++98.
@JonathanLeffler are you serious?? How the hell do they even maintain that? I.e. the compiler has to "detect" a return lacking and substitute 0 if not found, but only for main() ? Thats is hideous. And apparently gcc on ideone doesn't comply with that, because unless I explicitly added the return 0; a runtime error was reported after main() finished.
Yes, I'm serious. In ISO/IEC 9899:2011, §5.1.2.2.3 Program termination it says: If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument; reaching the } that terminates the main function returns a value of 0. Footnote 11 says: In accordance with 6.2.4, the lifetimes of objects with automatic storage duration declared in main will have ended in the former case, even where they would not have in the latter.
@JonathanLeffler just wow. I feel compelled to change #3 in the list, but at this point short of replicating comments here I've no idea what to put there. Its just... wrong. Obviously I'm inaccurate as-written in that statement, but what am I left with beyond "always return definitive results from main() because it makes you happy" =P
I didn't say I liked it. I put return 0; at the end of my own int main(void) { …; return 0; } and quietly do the same with other people's code if it uses C99 syntax or functions, but comment on it if the code is clearly C89. Note, though, that MSVC 2008 onwards documents void main() as valid too, so that can't necessarily be corrected either, but if it is int main(), it should also have return 0; at the end. Writing adequately nuanced answers is hard work!
|
0

It looks good to me. May I suggest giving it a prototype or moving your myfunc() definition before main(). Also assigning a value to result when it is declared. That will give you a better idea of what is going on if the function is not doing what you expect.

Comments

0

For some reason, the other answers just pointed out technical detail that's wrong, but failed to notice what is really wrong: You are returning the address of an array on the stack. But when the function returns, accessing that array becomes undefined behavior. Other code may freely overwrite the memory, leaving the worst possible garbage in it, or, conversely, writing to the memory behind the returned pointer may trash any vitally important variable of some other, entirely unconnected parts of the code.

If you want to return a pointer, you must either return a pointer to a static object, or you must return a pointer to something on the heap. Here is the static case:

char* foo() {
    static char staticArray[1024];
    return staticArray;
}

Using static here guarantees that the memory reserved for staticArray[] will remain reserved for it throughout the execution of your program. There are, however, three downsides of this:

  1. the array size is fixed at compile time

  2. this is generally not multithreading safe since all threads will use the same globally allocated memory

  3. you generally cannot expect the data behind the returned pointer to remain intact across a function call. Consider this code:

    void bar() {
        char* temp = foo();
        temp[0] = 7;
    }
    
    void baz() {
        char* temp = foo();
        temp[0] = 3;
        bar();
        //now temp[0] is 7 !
    }
    

This might be desirable in some rare cases, however, in most it's not.

So, if you want to be able to freely use the memory behind the returned pointer, you have to malloc() memory for it (and free() it afterwards, of course). Like this:

char* foo(int size) {
    return malloc(size);
}

void baz() {
    char* sevenBytes = foo(7);
    //Do something with seven bytes
    free(sevenBytes);
}

void bar() {
    char* threeBytes = foo(3);
    threeBytes[0] = 3;
    baz();
    assert(threeBytes[0] == 3);    //baz() worked on it's own memory
    free(threeBytes);
}

In the case of string handling, there is a number of handy functions available in the POSIX-2008 standard that do the memory allocation for you, among them strdup() and asprintf(). Here are some usage examples:

int main() {
    char* hello = strdup("Hello");
    char* greeting;
    if(0 > asprintf(&greeting, "%s World!\nMemory for hello was allocated at %llx", hello, (long long)hello)) {
        //error handling
    }
    printf(greeting);
    free(hello);
    free(greeting);
}

This will print something like:

Hello World!
Memory for hello was allocated at c726de80

3 Comments

Thank you. Yes other answers were not complete because I edited my initial problem. Your answer helped me very well, thank you too. Do you suggest me to use strdup and asprintf as often as I can?
I would use them whenever I know they are available. Unfortunately that is not the case everywhere, because not all systems conform to the POSIX standard. They were proposed for the C11 standard as well, but for some obscure reason, they were not included in its final version. They are available on any GNU/Linux system, though.
Ok, as I'm using CentOS 6 it is available.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.