I apologise for adding yet another answer but I don't think anyone has covered every point that needs to be covered in your question.
1) Whenever you use malloc()
to dynamically allocate some memory, you must also free()
it when you're done. The operating system will, usually, tidy up after you, but consider that you have a process during your executable that uses some memory. When said process is done, if you free()
that memory your process has more memory available. It's about efficiency.
To use free correctly:
int* somememory = malloc(sizeyouwant * sizeof(int));
// do something
free(somememory);
Easy.
2) Whenever you use malloc
, as others have noted, the actual allocation is in bytes so you must do malloc(numofelements*sizeof(type));
. There is another, less widely used, function called calloc
that looks like this calloc(num, sizeof(type));
which is possibly easier to understand. calloc also initialises your memory to zero.
3) You do not need to cast the return type of malloc
. I know a lot of programming books suggest you do and C++ mandates that you must (but in C++ you should be using new
/delete
). See this question.
4) Your function signature was indeed incorrect - function signatures must match their functions.
5) On returning pointers from functions, it is something I discourage but it isn't wrong per se. Two points to mention: always keep 1) in mind. I asked exactly what the problem was and it basically comes down to keeping track of those free()
calls. As a more advanced user, there's also the allocator type to worry about.
Another point here, consider this function:
int* badfunction()
{
int x = 42;
int *y = &x;
return y;
}
This is bad, bad, bad. What happens here is that we create and return a pointer to x
which only exists as long as you are in badfunction
. When you return, you have an address to a variable that no longer exists because x
is typically created on the stack. You'll learn more about that over time; for now, just think that the variable doesn't exist beyond its function.
Note that int* y = malloc(...
is a different case - that memory is created on the heap because of the malloc and therefore survives the end of said function.
What would I recommend as a function signature? I would actually go with shybovycha's function with a slight modification:
int findFactors(int* factors, const int N);
My changes are just personal preference. I use const
so that I know something is part of the input of a function. It isn't strictly necessary with just an int, but if you're passing in pointers, remember the source memory can be modified unless you use const
before it, whereon your compiler should warn you if you try to modify it. So its just habit in this case.
Second change is that I prefer output parameters on the left because I always think that way around, i.e. output = func(input)
.
Why can you modify function arguments when a pointer is used? Because you've passed a pointer to a variable. This is just a memory address - when we "dereference" it (access the value at that address) we can modify it. Technically speaking C is strictly pass by value. Pointers are themselves variables containing memory addresses and the contents of those variables are copied to your function. So a normal variable (say int
) is just a copy of whatever you passed in. int* factors
is a copy of the address in the pointer variable you pass in. By design, both the original and this copy point to the same memory, so when we dereference them we can edit that memory in both the caller and the original function.
I hope that clears a few things up.