What option is recommended in C to return an array from a function?
Option 1:
void function_a(int *return_array){
return_array[0] = 1;
return_array[1] = 0;
}
Option 2:
int* function_b(){
int return_array[2];
return_array[0] = 1;
return_array[1] = 0;
return return_array;
}
This function
int* function_b(){
int return_array[2];
return_array[0] = 1;
return_array[1] = 0;
return return_array;
}
returns a pointer to the first element of a local array with automatic storage duration that will not be alive after exiting the function.
So the returned pointer will be invalid and dereferencing such a pointer invokes undefined behavior.
You could return a pointer to first element of an array from a function if the array is allocated dynamically or has static storage duration that is when it is declared with the storage class specifier static.
As for the first function then it will be more safer if you will pass also the number of elements in the array like
void function_a(int *return_array, size_t n );
and within the function you will be able to check the passed value.
I'd most prefer:
void function_a(int return_array[const], size_t sz) {
return_array[0] = 1;
return_array[1] = 0;
}
Because it clearly indicates that the parameter is an Array, and it also clearly indicates the size of the array that is passed in, making out-of-bounds indicies less likely to be a problem.
Related
Is the following code (func1()) correct if it has to return i? I remember reading somewhere that there is a problem when returning a reference to a local variable. How is it different from func2()?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
This code snippet:
int& func1()
{
int i;
i = 1;
return i;
}
will not work because you're returning an alias (a reference) to an object with a lifetime limited to the scope of the function call. That means once func1() returns, int i dies, making the reference returned from the function worthless because it now refers to an object that doesn't exist.
int main()
{
int& p = func1();
/* p is garbage */
}
The second version does work because the variable is allocated on the free store, which is not bound to the lifetime of the function call. However, you are responsible for deleteing the allocated int.
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
Typically you would wrap the pointer in some RAII class and/or a factory function so you don't have to delete it yourself.
In either case, you can just return the value itself (although I realize the example you provided was probably contrived):
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
Note that it's perfectly fine to return big objects the same way func3() returns primitive values because just about every compiler nowadays implements some form of return value optimization:
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
Interestingly, binding a temporary to a const reference is perfectly legal C++.
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
A local variable is memory on the stack, and that memory is not automatically invalidated when you go out of scope. From a function deeper nested (higher on the stack in memory), it’s perfectly safe to access this memory.
Once the function returns and ends though, things get dangerous.
Usually the memory is not deleted or overwritten when you return, meaning the memory at that address is still containing your data - the pointer seems valid.
Until another function builds up the stack and overwrites it.
This is why this can work for a while - and then suddenly cease to function after one particularly deeply nested set of functions, or a function with really huge sized or many local objects, reaches that stack-memory again.
It even can happen that you reach the same program part again, and overwrite your old local function variable with the new function variable. All this is very dangerous and should be heavily discouraged.
Do not use pointers to local objects!
A good thing to remember are these simple rules, and they apply to both parameters and return types...
Value - makes a copy of the item in question.
Pointer - refers to the address of the item in question.
Reference - is literally the item in question.
There is a time and place for each, so make sure you get to know them. Local variables, as you've shown here, are just that, limited to the time they are locally alive in the function scope. In your example having a return type of int* and returning &i would have been equally incorrect. You would be better off in that case doing this...
void func1(int& oValue)
{
oValue = 1;
}
Doing so would directly change the value of your passed in parameter. Whereas this code...
void func1(int oValue)
{
oValue = 1;
}
would not. It would just change the value of oValue local to the function call. The reason for this is because you'd actually be changing just a "local" copy of oValue, and not oValue itself.
I have the following code:
intlist* create_list(int *arr) {
intlist* l = malloc(sizeof(intlist));
while(*arr++) {
l->sum += *arr;
//*arr++;
}
return l;
}
void printl(intlist* l) {
printf("%d\n", l->sum);
}
When I print *arr inside the while loop it shows the correct value. The issue is after I come out of the function, create_list, and try to access the sum of the list, it is completely wrong. It is not, for example, 1 + 2 + 3 = 6 but rather something like -123871239012. What am I doing wrong?
I am not looking for a function to pass the array size to, because that is a very dangerous method to use, in my opinion and experience, most situations. I do not want to pass the size of the array because if I accidentally write "1239123" instead of "1239122" I might do something bad. Or even worse, if I accedentally write "1239123" instead of "123912" where I did not press the "3" in the last place it will have devastating effects.
There are two problems with the function create_list
intlist* create_list(int *arr) {
intlist* l = malloc(sizeof(intlist));
while(*arr++) {
l->sum += *arr;
//*arr++;
}
return l;
}
The first one is that the data member sum was not initialized.
The second one is that the first element of the array is ignored due to the post-increment in the condition of the while loop
while(*arr++) {
You should at least write
while(*arr) {
l->sum += *arr;
arr++;
}
Pay attention to that you should check whether the memory was allocated successfully for an object of the type intlist before passing the control to the while loop.
The function expects that the array contains an element with the sentinel value equal to 0.
If the function must deal with arrays that do not have an element with the sentinel value then you have to declare a second parameter that will specify how many elements there are in the passed array.
Pay attention to that the first parameter should have the qualifier const because the passed array is not being changed within the function.
That is the function should be declared like
intlist * create_list( const int *arr, size_t n );
Some errors:
while(*arr++) {
l->sum += *arr;
//*arr++;
}
You will add the *arr after the arr incrementation.
To illustrate this problem: https://godbolt.org/z/5qe9cE
It has to be:
while(*arr) {
l->sum += *arr++;
//*arr++;
}
the malloced memory is not initialized and structure members have undetermined values (it can be anything). Before the loop you need to
l->sum = 0;
The array has to be 0 terminated for example
int array[] = {1,2,3,4,5,6,0};
https://godbolt.org/z/c8cPGs
The code below is producing a compiler warning: return from incompatible pointer type. The type I'm returning seems to be the issue but I cant seem to fix this warning.
I have tried changing the type of hands to int *. Also have tried returning &hands.
int * dealDeck(int numPlayers, int numCards, int cardDeck[])
{
static int hands[MAX_PLAYERS][MAX_CARDS]={0};
int start = 0;
int end = numCards;
int player, hand, j;
int card;
for(player = 0; player < numPlayers; player++)
{
for(hand = start, j=0; hand < end; hand++,j++)
{
card = cardDeck[hand];
hands[player][j] = card;
}
start = end;
end += numCards;
}
return hands;
}
This function should return a pointer to the array "hands". This array is then passed to another function which will print out its elements.
The hands variable is not an int * this is a int **
So you need to return a int **
This is a 2d array.
First of all, you have declared return type of int *, which would mean, that you are trying to return an array, while you want to return a 2-dimensional array. The proper type for this would usually be int **, but that won't cut it here. You opted to go with static, fixed size array. That means, that you need to return pointer to some structures of size MAX_CARDS * sizeof(int) (and proper type, which is the real problem here). AFAIK, there is no way to specify that return type in C*.
There are many alternatives though. You could keep the static approach, if you specify only up to 1 size (static int *hands[MAX_PLAYERS] or static int **hands), but then you need to dynamically allocate the inner arrays.
The sane way to do it is usually "call by reference", where you define the array normally before calling the function and you pass it as a parameter to the function. The function then directly modifies the outside variables. While it will help massively, with the maintainability of your code, I was surprised to find out, that it doesn't get rid of the warning. That means, that the best solution is probably to dynamically allocate the array, before calling the function and then pass it as an argument to the function, so it can access it. This also solves the question of whether the array needs to be initialized, and whether = {0} is well readable way to do it (for multidimensional array) , since you'll have to initialize it "manually".
Example:
#include <stdio.h>
#include <stdlib.h>
#define PLAYERS 10
#define DECKS 20
void foo(int **bar)
{
bar[0][0] = 777;
printf("%d", bar[0][0]);
/*
* no point in returning the array you were already given
* but for the purposes of curiosity you could change the type from
* void to int ** and "return bar;"
*/
}
int main()
{
int **arr;
arr = malloc(sizeof(int *) * PLAYERS);
for (size_t d = 0; d < DECKS; d++) {
/* calloc() here if you need the zero initialization */
arr[d] = malloc(sizeof(int) * DECKS);
}
foo(arr);
return 0;
}
*some compilers call such type like int (*)[20], but that isn't valid C syntax
I'm calling a function which returns a 3D array. The problem is that if I declare the array inside the function it returns a dangling pointer as the execution of the program goes out of the scope of the variable. But when I declare the array outside the function, it gives Error:'array' was not declared in this scope. How should I declare the array? It returns integer type.
int arr[x][y][z];
int func(list of parameters)
{
//code
return arr;
}
int main()
{
int arr2[x][y][z];
arr2 = func(list of parameters);
return 0;
}
You try to return an integer value with a name arr, but you did not define int arr in the function scope.
C does not allow to return array by value. You need to pass a pointer to an array to the function in order to let it to modify array.
Something like:
void func(int*** array, <list of parameters>)
{
//code
array[1][2][4] = 10;
}
int main()
{
int arr2[x][y][z];
func(arr2, <list of parameters>);
return 0;
}
few problems in your code:
First, func function should return an int*** pointer. it is defined as returning int which is not the type you actually return.
Second, why retuning the global arr array from func? it simply modifies the global array.
int arr[x][y][z];
int func(list of parameters)
{
//code
return arr;
}
Third, why declaring arr2 to hold the result - simply reference the global array you've defined.
Fourth, defining int arr[x][y][z]; globally is not supported - the compiler would not know how to create this buffer - you should declare it with actual size to the array (e.g., int arr[10][10][10];
Either pass the array as a parameter in the function if you are declaring it outside the function or if you are declaring it inside the function then to deal with a dangling pointer
is for example -
char*func()
{
char str[10];
strcpy(str,"Hello!");
return(str);
}
//returned pointer points to str which has gone out of scope.
or you might be using memory that is being freed for example
int *c = malloc(sizeof(int));
free(c);
*c = 3; //writing to freed location!
I've just started to work with C, and never had to deal with pointers in previous languages I used, so I was wondering what method is better if just modifying a string.
pointerstring vs normal.
Also if you want to provide more information about when to use pointers that would be great. I was shocked when I found out that the function "normal" would even modify the string passed, and update in the main function without a return value.
#include <stdio.h>
void pointerstring(char *s);
void normal(char s[]);
int main() {
char string[20];
pointerstring(string);
printf("\nPointer: %s\n",string);
normal(string);
printf("Normal: %s\n",string);
}
void pointerstring(char *s) {
sprintf(s,"Hello");
}
void normal(char s[]) {
sprintf(s,"World");
}
Output:
Pointer: Hello
Normal: World
In a function declaration, char [] and char * are equivalent. Function parameters with outer-level array type are transformed to the equivalent pointer type; this affects calling code and the function body itself.
Because of this, it's better to use the char * syntax as otherwise you could be confused and attempt e.g. to take the sizeof of an outer-level fixed-length array type parameter:
void foo(char s[10]) {
printf("%z\n", sizeof(s)); // prints 4 (or 8), not 10
}
When you pass a parameter declared as a pointer to a function (and the pointer parameter is not declared const), you are explicitly giving the function permission to modify the object or array the pointer points to.
One of the problems in C is that arrays are second-class citizens. In almost all useful circumstances, among them when passing them to a function, arrays decay to pointers (thereby losing their size information).
Therefore, it makes no difference whether you take an array as T* arg or T arg[] — the latter is a mere synonym for the former. Both are pointers to the first character of the string variable defined in main(), so both have access to the original data and can modify it.
Note: C always passes arguments per copy. This is also true in this case. However, when you pass a pointer (or an array decaying to a pointer), what is copied is the address, so that the object referred to is accessible through two different copies of its address.
With pointer Vs Without pointer
1) We can directly pass a local variable reference(address) to the new function to process and update the values, instead of sending the values to the function and returning the values from the function.
With pointers
...
int a = 10;
func(&a);
...
void func(int *x);
{
//do something with the value *x(10)
*x = 5;
}
Without pointers
...
int a = 10;
a = func(a);
...
int func(int x);
{
//do something with the value x(10)
x = 5;
return x;
}
2) Global or static variable has life time scope and local variable has scope only to a function. If we want to create a user defined scope variable means pointer is requried. That means if we want to create a variable which should have scope in some n number of functions means, create a dynamic memory for that variable in first function and pass it to all the function, finally free the memory in nth function.
3) If we want to keep member function also in sturucture along with member variables then we can go for function pointers.
struct data;
struct data
{
int no1, no2, ans;
void (*pfAdd)(struct data*);
void (*pfSub)(struct data*);
void (*pfMul)(struct data*);
void (*pfDiv)(struct data*);
};
void add(struct data* x)
{
x.ans = x.no1, x.no2;
}
...
struct data a;
a.no1 = 10;
a.no1 = 5;
a.pfAdd = add;
...
a.pfAdd(&a);
printf("Addition is %d\n", a.ans);
...
4) Consider a structure data which size s is very big. If we want to send a variable of this structure to another function better to send as reference. Because this will reduce the activation record(in stack) size created for the new function.
With Pointers - It will requires only 4bytes (in 32 bit m/c) or 8 bytes (in 64 bit m/c) in activation record(in stack) of function func
...
struct data a;
func(&a);
...
Without Pointers - It will requires s bytes in activation record(in stack) of function func. Conside the s is sizeof(struct data) which is very big value.
...
struct data a;
func(a);
...
5) We can change a value of a constant variable with pointers.
...
const int a = 10;
int *p = NULL;
p = (int *)&a;
*p = 5;
printf("%d", a); //This will print 5
...
in addition to the other answers, my comment about "string"-manipulating functions (string = zero terminated char array): always return the string parameter as a return value.
So you can use the function procedural or functional, like in printf("Dear %s, ", normal(buf));