tags:

views:

152

answers:

8

Which is considered better style?

int set_int(int *source){
 *source = 5;
 return 0;
}

int main(){
 int x*;
 set_int(x);
}

OR

int *set_int(){
 int *temp = NULL;
 temp = malloc(sizeof (int));
 *temp = 5;
 return temp;
}

int main(){
 int *x = set_int();
}

Coming for a higher level programming background I gotta say I like the second version more. Any, tips would be very helpful. Still learning C.

+3  A: 

Neither.

// "best" style for a function which sets an integer taken by pointer
void set_int(int *p) { *p = 5; }

int i;
set_int(&i);

Or:

// then again, minimise indirection
int an_interesting_int() { return 5; /* well, in real life more work */ }
int i = an_interesting_int();

Just because higher-level programming languages do a lot of allocation under the covers, does not mean that your C code will become easier to write/read/debug if you keep adding more unnecessary allocation :-)

If you do actually need an int allocated with malloc, and to use a pointer to that int, then I'd go with the first one (but bugfixed):

void set_int(int *p) { *p = 5; }

int *x = malloc(sizeof(*x));
if (x == 0) { do something about the error }
set_int(x);

Note that the function set_int is the same either way. It doesn't care where the integer it's setting came from, whether it's on the stack or the heap, who owns it, whether it has existed for a long time or whether it's brand new. So it's flexible. If you then want to also write a function which does two things (allocates something and sets the value) then of course you can, using set_int as a building block, perhaps like this:

int *allocate_and_set_int() {
    int *x = malloc(sizeof(*x));
    if (x != 0) set_int(x);
    return x;
}

In the context of a real app, you can probably think of a better name than allocate_and_set_int...

Steve Jessop
It's sort of a contrived example, normally I would of course just return 5. I guess what I want to know is the best way to handle playing with pointer values going in and out of functions.
LearningC
+1  A: 

In the second one you would need a pointer to a pointer for it to work, and in the first you are not using the return value, though you should.

I tend to prefer the first one, in C, but that depends on what you are actually doing, as I doubt you are doing something this simple.

Keep your code as simple as you need to get it done, the KISS principle is still valid.

James Black
+2  A: 

Some errors:

int main(){
 int x*;  //should be int* x; or int *x;
 set_int(x);
}

Also, you are not allocating any memory in the first code example.

int *x = malloc(sizeof(int));

About the style:
I prefer the first one, because you have less chances of not freeing the memory held by the pointer.

N 1.1
Yah, int x* was a typo. Meant, int *x
LearningC
Ok. But **do** allocate the memory.
N 1.1
+1  A: 

Definitely go with the first version. Notice that this allowed you to omit a dynamic memory allocation, which is SLOW, and may be a source of bugs, if you forget to later free that memory.

Also, if you decide for some reason to use the second style, notice that you don't need to initialize the pointer to NULL. This value will either way be overwritten by whatever malloc() returns. And if you're out of memory, malloc() will return NULL by itself, without your help :-). So int *temp = malloc(sizeof(int)); is sufficient.

slacker
I agree that for this question (in particular, a quantity as small as an int) using the heap is stupid, but... Not using malloc because it might be a source of bugs if you use it wrong? That's kind of unreasonable. Lots of things introduce bugs if you use them wrong. Doesn't mean that feature doesn't have a use.
asveikau
@asveikau:Of course it doesn't. Still, if you don't get anything from it, why risk? Also, that was a side note on my side, the main argument being about inefficiency. The `int` was an example, though. The question was about the general technique. Surely you don't want to return a 2kB `struct` by value :).
slacker
+1  A: 

Memory managing rules usually state that the allocator of a memory block should also deallocate it. This is impossible when you return allocated memory. Therefore, the second should be better.

For a more complex type like a struct, you'll usually end up with a function to initialize it and maybe a function to dispose of it. Allocation and deallocate should be done separately, by you.

C gives you the freedom to allocate memory dynamically or statically, and having a function work only with one of the two modes (which would be the case if you had a function that returned dynamically allocated memory) limits you.

typedef struct
{
    int x;
    float y;
} foo;

void foo_init(foo* object, int x, float y)
{
    object->x = x;
    object->y = y;
}

int main()
{
    foo myFoo;
    foo_init(&foo, 1, 3.1416);
}
zneak
+2  A: 

The first one is incorrect (apart from the syntax error) - you're passing an uninitialised pointer to set_int(). The correct call would be:

int main()
{
    int x;
    set_int(&x);
}

If they're just ints, and it can't fail, then the usual answer would be "neither" - you would usually write that like:

int get_int(void)
{
    return 5;
}

int main()
{
    int x;
    x = get_int();
}

If, however, it's a more complicated aggregate type, then the second version is quite common:

struct somestruct *new_somestruct(int p1, const char *p2)
{
    struct somestruct *s = malloc(sizeof *s);

    if (s)
    {
        s->x = 0;
        s->j = p1;
        s->abc = p2;
    }

    return s;
}

int main()
{
    struct somestruct *foo = new_somestruct(10, "Phil Collins");

    free(foo);

    return 0;
}

This allows struct somestruct * to be an "opaque pointer", where the complete definition of type struct somestruct isn't known to the calling code. The standard library uses this convention - for example, FILE *.

caf
A: 

It is best not to return a piece of allocated memory from a function if somebody does not know how it works they might not deallocate the memory. The memory deallocation should be the responsibility of the code allocating the memory.

Romain Hippeau
A: 

The first is preferred (assuming the simple syntax bugs are fixed) because it is how you simulate an Out Parameter. However, it's only usable where the caller can arrange for all the space to be allocated to write the value into before the call; when the caller lacks that information, you've got to return a pointer to memory (maybe malloced, maybe from a pool, etc.)

Donal Fellows