Passing Array By Reference To Function in C - c

I'm having a real difficult time getting this code to work. I'm trying to pass an array by reference to a function, in order to modify it in that function. Then I need the modifications to be handed back to the original caller function.
I have searched here for a similar problem, but couldn't find anything that can run successfully like the way I want to do it.
Here's my code, I would really appreciate any help. Thanks a lot:
#include <stdio.h>
#include <stdlib.h>
#define SIZE_OF_VALUES 5
#define SIZE_OF_STRING 100
void set_values(char **values);
void set_values(char **values)
{
*values = malloc(sizeof(char)*SIZE_OF_VALUES);
for (int i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++) {
values[i] = malloc(sizeof(char)*SIZE_OF_STRING);
values[i] = "Hello";
//puts(values[i]); //It works fine here.
}
}
int main (int argc, const char * argv[])
{
char *values;
set_values(&values);
for (int i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++) {
puts(values[i]); //It does not work!
}
return 0;
}

There are several problems with your code:
You should have three-level pointers - void set_values(char ***values), read it as a "a reference (first *) to an array (second *) of char* (third *)"
Each element in *values should be a pointer (char*) not char, so you need:
*values = malloc(sizeof(char*)*SIZE_OF_VALUES);
You are leaking memory, first mallocing then assigning literal, and additionally not dereferencing values, you need either:
(*values)[i] = "Hello";
or
(*values)[i] = strdup("Hello"); // you will have to free it later
or
(*values)[i] = malloc(sizeof(char)*SIZE_OF_STRING); // you will have to free this as well
strcpy((*values)[i], "Hello");
In your main, you should declare char **values; as it is a pointer to an array of char* (character string/array).
In you loop you are incorrectly multiplying indices by sizeof, index is counted in elements not in bytes. Thus, you need:
for (int i = 0; i < SIZE_OF_VALUES; i++)
Don't forget to free the memory at the end.

Use a char *** type for your parameter of your set_values function:
#include <stdio.h>
#include <stdlib.h>
#define SIZE_OF_VALUES 5
void set_values(char ***values)
{
*values = malloc(sizeof (char *) * SIZE_OF_VALUES);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
(*values)[i] = "Hello";
}
}
int main (int argc, char *argv[])
{
char **values;
set_values(&values);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
puts(values[i]);
}
return 0;
}
Of course you have to check for malloc return value and free allocated memory before exit of main.

Here is the solution.
void set_values(char ***values)
{
int i;
char ** val;
val = *values = (char**)malloc(sizeof(char*)*SIZE_OF_VALUES);
for (i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++)
val[i] = "Hello";
}
int main (int argc, const char * argv[])
{
char **values;
int i;
set_values(&values);
for (i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++)
puts(values[i]);
return 0;
}

char * is a one dimensional array of char. but you want your code in set_values sets values to a two dimensional array.
In order to make this work, define:
values as char **values;
set_values as void set_values(char ***values)
allocate the pointers for the char arrays as:
*values = malloc(sizeof(char*)*SIZE_OF_VALUES);
Besides that your loop is a bit strange:
for (int i = 0; i < (sizeof(char)*SIZE_OF_VALUES); i++) {
should be replaced with
for (int i = 0; i < SIZE_OF_VALUES; i++) {
and finally, if you want to copy a string into your now allocated array use
strncpy((*values)[i], "Hello", SIZE_OF_STRING-1);
(*values)[i][SIZE_OF_STRING-1] = '\0';
so in total:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_OF_VALUES 5
#define SIZE_OF_STRING 100
void set_values(char ***values);
void set_values(char ***values)
{
const char * content = "Hello";
*values = malloc(sizeof(char*)*SIZE_OF_VALUES);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
(*values)[i] = malloc(sizeof(char)*SIZE_OF_STRING);
strncpy((*values)[i], content, SIZE_OF_STRING-1);
(*values)[i][SIZE_OF_STRING-1] = '\0';
if(strlen(content) >= SIZE_OF_STRING){
fprintf(stderr,"Warning content string did not fit into buffer!\n");
}
}
}
int main (int argc, const char * argv[])
{
char **values;
set_values(&values);
for (int i = 0; i < SIZE_OF_VALUES; i++) {
printf("%s\n", values[i]);
}
for (int i = 0; i < SIZE_OF_VALUES; i++) {
free(values[i]);
}
free(values);
return 0;
}

You have an extra * in this line:
*values = malloc(sizeof(char)*SIZE_OF_VALUES);
Which should be:
values = malloc(sizeof(char)*SIZE_OF_VALUES);
Also you have considerable problem in your main, char* values should be char** values, passing your char* values by reference (set_values(&values);) may cause segmentation fault I suspect.
For affecting the outer array, it's already being affected because when passing to the function you are only copying a pointer that points to the same place, so the modifications will affect the same memory blocks.

Related

C: How to free memory after realloc for string arrays

I'm learning C and want to create a simple function which keeps track of a list of paths.
I start with a default path ["/bin/"] and have a function "change_paths" which updates this list based on some input, so for example ["/bin/"] -> ["/temp/", "/auxillary/"].
However, I encounter problems when I try to free my memory at the end. Specifically, fsanitize tells me that the 6 bytes from my default PATH paths[0] = malloc(6 * sizeof(char)); are not freed properly.
What should I do to correctly free this memory if I use change_paths arbitrarily many times with arbitrarily many inputs (including possibly 0 new PATHs)? Is this structure appropriate for storing data with this mechanism?
Note: I've edited this code for brevity, so even though the line "char** new_paths = {"/temp/", "/auxillary/"};" is not technically correct, please think of it as working. I just want to give an example and I'm not sure how to define a char** manually.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void change_paths(int *num_paths, char*** paths, int num_new_paths, char** new_paths){
*paths = realloc(*paths, num_new_paths * sizeof(char*));
for (int i = 0; i < num_new_paths; i++){
*paths[i] = malloc((strlen(new_paths[i]) + 1) * sizeof(char));
strcpy(*paths[i], new_paths[i]);
}
}
int main(int argc, char *argv[]){
// A Default PATH
char** paths = malloc(1 * sizeof(char*));
paths[0] = malloc(6 * sizeof(char)); // <- HOW TO FREE THIS AFTER REALLOC OF paths?
strcpy(paths[0], "/bin/");
int num_paths = 1;
// A new set of PATHs
int num_new_paths = 2;
char** new_paths = {"/temp/", "/auxillary/"};
change_paths(&num_paths, &paths, num_new_paths, new_paths);
// Free memory
for(int i = 0; i < num_new_paths; i++){
free(paths[i]);
}
free(paths);
return 0;
}
You need to keep track of the number of old path entries, and free each one before you overwrite the reallocated space with new path entries.
void change_paths(int *num_paths, char ***paths, int num_new_paths, char **new_paths)
{
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
*paths = realloc(*paths, num_new_paths * sizeof((*paths)[0]));
for (int i = 0; i < num_new_paths; i++)
{
(*paths)[i] = malloc((strlen(new_paths[i]) + 1));
strcpy((*paths)[i], new_paths[i]);
}
*num_paths = num_new_paths;
}
Consider using strdup() in the second loop:
void change_paths(int *num_paths, char ***paths, int num_new_paths, char **new_paths)
{
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
*paths = realloc(*paths, num_new_paths * sizeof((*paths)[0]));
for (int i = 0; i < num_new_paths; i++)
(*paths)[i] = strdup(new_paths[i]));
*num_paths = num_new_paths;
}
Also, don't forget to error check memory allocations and handle them appropriately. Note that the idiom:
old_space = realloc(old_space, new_size);
leaks memory if the reallocation fails. It is important to use:
void *new_space = realloc(old_space, new_size);
if (new_space == NULL)
…deal with error…
old_space = new_space;
That leads to this code:
void change_paths(int *num_paths, char ***paths, int num_new_paths, char **new_paths)
{
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
*num_paths = 0; // In case realloc fails
void *new_space = realloc(*paths, num_new_paths * sizeof((*paths)[0]));
if (new_space == NULL)
return;
*paths = new_space;
for (int i = 0; i < *num_paths; i++)
free((*paths)[i]);
for (int i = 0; i < num_new_paths; i++)
(*paths)[i] = strdup(new_paths[i]));
*num_paths = num_new_paths;
}
Note that if strdup() fails, some of the entries in the array may be null pointers. You could use other error handling for failures in strdup().
Warning: no compiler was consulted about the validity of any of this code.

C how to return arrays from multiple functions?

I am trying to make a program that first creates an array in another function, returns it and then calls another function that shuffles the contents of the array and returns it. However I am struggling to do this in C since I do not quite understand the array pointer system that has to be used here.
So far my code doesnt return the values 1-20 from makeArray() but instead returns an array full of 0s and I have a feeling it has to do with the c's array pointer system.
Any help would greatly be appreciated! Thank you in advance
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int arrShuffle();
int arrShuffle(int * arr) {
int arr[21];
// shuffle array
for(int j=0; j<20; j++) {
int randInd = (rand() % 20) + 1;
int temp = arr[j];
arr[j] = arr[randInd];
arr[randInd] = temp;
}
return arr;
}
int makeArray() {
int arr[21];
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
void main() {
int *orgArr;
int *modArr;
srand(time(NULL));
orgArr = makeArray();
for(int i=0; i < 20; i++) {
printf("OrgArr: %d\n", orgArr);
}
modArr = arrShuffle(orgArr);
}
You cannot use variables with automatic storage (aka local ones). You must allocate the array so the memory remains valid after the function ends:
int* makeArray() {
int *arr = calloc(21, sizeof *a);
// make array of 1-20
for(int i=0; i < 20; i++) {
arr[i] = i + 1;
}
return arr;
}
Remember to release the array when it is no longer used:
int main() {
int *orgArr;
...
orgArr = makeArray();
...
free(orgArr);
}
As tstanisl pointed out in their answer, a possible solution is to use dynamic memory allocation. My answer, instead, will give you yet another solution: using an array passed by the caller.
NOTE: both solutions are valid and their usefulness depends on the specific needs of your program. There's no "right" universal solution.
void makeArray(int arr[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
arr[i] = (int) (i + 1);
}
}
void cloneAndModifyArray(const int orig[], int new[], size_t len) {
for (size_t i = 0; i < len; i += 1) {
new[i] = orig[i] * 2; // or some other modification
}
}
And you use it like this:
#define ARR_LEN (100)
int main(void) {
int arr[ARR_LEN];
makeArray(arr, ARR_LEN);
int modified_arr[ARR_LEN];
cloneAndModifyArray(arr, modified_arr, ARR_LEN);
return 0;
}

How to return an array of char pointers? What is wrong in my code?

I have seen similar posts related to my question but I could not find any answer to understand the bug in this code.
So, I have a function whose return type can't be changed (for case 1). For case 2, I would like to know how to return char *a[];
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **myfunc(int n) {
char **a = malloc(n * sizeof(char *));
int i, j = 1;
for (i = 0; i < n; i++)
a[i] = malloc(9 * sizeof(char));
for (i = 0; i < n; i++) {
snprintf(a[i], 5, "%d", i);
return a;
}
int main() {
int num = 10, i;
char **ar = myfunc(num);
for (i = 0; i < num; i++)
printf("%s\n", ar[i]);
return 0;
}
1) In the myfunc(), how should I return a correctly? My compiler is throwing me a warning that return from incompatible pointer type.
2) In case, if I change my above myfunc() as follows, how should I return the modified buffer?
char ???myfunc(int n) {
char *a[n];
for (i = 0; i < n; i++)
a[i] = malloc(10 * sizeof(char));
return ?
}
3) In both cases, how should I handle the return inside the main() function?
Case 2:
char *myfunc(int n) {
static char *a[n];
int i;
for (i = 0; i < n; i++)
a[i] = malloc(9 * sizeof(char));
for (i = 0; i < n; i++)
snprintf(a[i], 5, "%d", i);
return a;
}
int main() {
int num = 10, i;
char *ar = myfunc(num);
for (i = 0; i < num; i++)
printf("%s\n", ar[i]);
return 0;
}
Your code was mis-indented, which makes it hard to read and hides silly mistakes such as the extra brace after the second for.
Once corrected for this mistake, the code compiles and runs fine:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **myfunc(int n) {
char **a = malloc(n * sizeof(char *));
int i;
for (i = 0; i < n; i++)
a[i] = malloc(9 * sizeof(char));
for (i = 0; i < n; i++)
snprintf(a[i], 9, "%d", i);
return a;
}
int main() {
int num = 10, i;
char **ar = myfunc(num);
for (i = 0; i < num; i++)
printf("%s\n", ar[i]);
return 0;
}
If you change myfunc() to define a as char *a[n];, you have a major problem when returning a from myfunc() as the array is defined only inside the scope of myfunc(). Returning its address, which is simply return a; will cause undefined behavior in main() because the space it points to might have been reused for other stuff, such as printf() local variables.
The third option where you define a as static char *a[n]; does not compile because the size of static objects must be known at compile time. Using local static objects is not advisable as it makes the program harder to understand and non-reentrant, with hidden internal state, etc. One such function is strtok() from <string.h>.

How do I pass by reference char * foo[SIZE][SIZE] to a function and dereference it?

I'm really having a difficult time understanding how to pass the address of a 2D array of char pointers to a function, and actually assigning a value to it.
void fillWithStrings( 'pointer to foo' ){ // How to do this part?
for( int i = 0; i < SIZE; i++ ) {
for( int j = 0; j < SIZE; j++ ) {
char * temp = malloc( sizeof(char) * 3 );
temp = "hi";
*foo[i][j] = temp; // And this part?
}
}
}
int main(){
char * foo[SIZE][SIZE];
fillWithStrings( &foo );
return 0;
}
And yes, it is easier to fill foo in the scope where it was declared, but the point is, how to do it inside another function?
There is no need to pass the address of foo to fillWithStrings(), as the function does not want to change the value of foo (which, BTW, wouldn't even be possible as foo is an array).
Just pass foo, which then would decay to a pointer to is 1st element. It's 1st element is a char * [SIZE], the address to the latter is char * (*) [SIZE].
Code doing so might look like this:
#include <stdio.h>
#include <stdlib.h>
#define SIZE (7)
int array_init(char * (*a)[SIZE])
{
for (size_t i = 0; i < SIZE; ++i)
{
for (size_t j = 0; j < SIZE; ++j)
{
a[i][j] = calloc(42, sizeof *(a[i][j])); /* Allocate 42 times the size of
what (a[i][j]) points , that is a char.*/
if (NULL == a[i][j])
{
return -1;
}
}
}
return 0;
}
int main(void)
{
char * a[SIZE][SIZE] = {0};
if (-1 == array_init(a))
{
perror("array_init() failed");
exit(EXIT_FAILURE);
}
/* Do stuff. */
/* Free a's elements here. */
return EXIT_SUCCESS;
}
First of all, there is no such thing as passing by reference in C. Everything is passed by value. An array is "passed" as pointer to its first element. This pointer is also passed by value. It is being copied as function argument, but the array that it points at is left as it is, and can be seen from your function.
char * foo[SIZE][SIZE] is a two-dimensional array of character pointers. These pointers may point to charactres or arrays of characters. Since there is no specifiation of the size of these arrays of characters, from your code fillWithStrings() it can be assumed that these arrays are intended to be \0 terminated strings of characters.
Running this demonstration code may help better understand what is going on in your function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 4
void fillWithStrings( char* (foo)[SIZE][SIZE] ){
for( int i = 0; i < SIZE; i++ ) {
for( int j = 0; j < SIZE; j++ ) {
char * temp = malloc( 3 ); //sizeof(char) is always 1
if (j % 2) strcpy(temp, "lo");
else strcpy(temp,"hi");
foo[i][j] = temp;
}
}
}
int main(){
char * foo[SIZE][SIZE];
fillWithStrings( foo );
for( int i = 0; i < SIZE; i ++)
for (int j = 0; j < SIZE; j++)
printf("[%d][%d] = %s\n", i, j, foo[i][j]);
return 0;
}
For the first part the replace 'pointer to foo' with char* (*foo)[SIZE][SIZE]
This breaks down as follows:
(*foo) means foo is a pointer to something,
(*foo)[SIZE][SIZE] means foo points to a 2D array of somethings,
char* (*foo)[SIZE][SIZE] means foo points to a 2D array of pointers to char.
The use of the parentheses is necessary to avoid this being interpreted as a 2D array of pointers to pointers to char.
For the second part, (*foo)[i][j] = temp;
(*foo) will get the original array foo points to and
(*foo)[i][j] specifies where in that array the assignment will go.
EDIT: fixed second part and added explanations
This should work:
typedef char *FOO_TYPE [SIZE][SIZE]; // Or whatever your size/name is
void fillWithStrings (FOO_TYPE& foo)
{
}
You can then use it exactly as if it were declared locally.

memory allocation - call by reference String-Array-Paramater

The question is how to correctly allocate/free the memory in this example:
void test(char*** array, int* count) {
*array = malloc(sizeof(char*) * MAX_ARRAY);
while (...) {
(*array)[i] = (char*)malloc(strlen(fooString));
}
}
call of the function:
char** array;
int count;
test(&array, &count);
// now free the memory - i think i have to?
for(i = 0; i < count; i++) {
free(array[i]); // <-- crash here
}
free(array);
It looks like that array[0] has a different address inside the test-function than outside. How can this be? Looks like i misunderstood sth, because the address of array is the same outside and inside the function.
Edit: The Problem is that i am not able to free the allocated memory (see "crash here" in code). Why? And how will it work?
Instead of
void test(char*** array, int* count) {
*array = malloc(sizeof(char*) * MAX_ARRAY);
while (...) {
(*array)[i] = (char*)malloc(strlen(fooString));
}
}
do
void test(char*** array, int count) {
*array = malloc(sizeof(char*) * count); // number of pointers
for (int i = 0; i < count; ++i)
{
(*array)[i] = malloc(strlen(fooString));
}
}
although i am not sure about what fooString is since you don't show the decl/def. Normally you would allocate one byte extra for the \0
(*array)[i] = malloc(strlen(fooString) + 1)
this seems to work
#include <stdio.h>
#include <inttypes.h>
#include <malloc.h>
#include <string.h>
char fooString[256];
void test(char*** array, int count)
{
int i = 0;
*array = malloc(sizeof(char*) * count);
for (i = 0; i < count; ++i)
{
(*array)[i] = malloc(strlen(fooString)+1);
}
}
int main()
{
char** array = NULL;
int count = 100;
int i = 0;
test(&array, count);
for(i = 0; i < count;++i)
{
free(array[i]);
}
free(array);
return 0;
}
For your particular problem:
You allocate (*array)[i] which is a char* to strlen(fooString) which is usually equivalent to sizeof(char) * strlen(fooString) : this is error prone. You should use sizeof(*((*array)[i])) in this case to be sure not to miss the correct type.
To free it, loop from i = 0 to i < MAX_ARRAY and call free(array[i])
What you put in place of ... in your code is very important.
In general, when allocating memory, be sure to respect these general ideas:
If a functions allocates memory it frees it itself except when it is needed outside afterwards.
If a function allocates memory needed outside afterwards, it does just this.
This allows for better code architecture and easier freeing of the memory.
For example:
First point:
void foo()
{
char *a;
a = malloc(sizeof(*a) * 5);
a[0] = 'a';
a[1] = 'b';
a[2] = 'c';
a[3] = 'd';
a[4] = 0; //or '\0' if you prefer
do_something_cool(a);
free(a);
}
The function foo allocates memory, processes it, and frees it.
Second point:
char *halfstrdup(char *str)
{
int len;
int i;
char *newstr;
len = strlen(str);
newstr = malloc(sizeof(*newstr) * len / 2)
for (i = 0; i < len; i++)
{
if ((i % 2) == 0)
newstr[i / 2] = str[i];
}
return (newstr);
}
void foo2()
{
char *half;
half = halfstrdup("Hello, world !");
do_something_cooler(half);
free(half);
}
The function halfstrdup just allocates and sets the memory you need and returns it, the function foo2 allocates memory through the use of halfstrdup, then uses it and frees it.
Do not forget to free before losing track of your pointers, for example after returning from foo or foo2, you won't be able to free the allocated memory.

Resources