I have been trying to send a pointer to a pointer (we can call it an array of strings, or an array of an array of chars even) to a function, by reference, because I need it to be updated. I don't want to have the function returning the pointer to a pointer (that one I got working) because I want the return to be the size of the array.
This is a working function I created for testing purposes, which returns the pointer to a pointer, and the calling method:
#include <stdio.h>
char **populate_items() {
char **items;
int i;
items = (char **) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(items+i) = (char *) malloc(sizeof(char) * 10);
items[0] = "1234567890";
items[1] = "2345678901";
items[2] = "3456789012";
return items;
}
int main(int argv, char *argc) {
char **items;
int i;
items = populate_items();
for(i=0; i<3; i++)
printf("%s\n", items[i]);
return 0;
}
This is what I THINK the function and the call to the function that gets the pointer to a pointer as reference should look like, but I get a segmentation fault when trying to print items[1] or items[2]
#include <stdio.h>
populate_items(char ***items) {
int i;
*items = (char **) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(items+i) = (char *) malloc(sizeof(char) * 10);
*items[0] = "1234567890";
*items[1] = "2345678901";
*items[2] = "3456789012";
}
int main(int argv, char *argc) {
char **items;
int i;
populate_items(&items);
for(i=0; i<3; i++)
printf("%s\n", items[i]);
return 0;
}
In the abstraction that I created in my head, the function should be fine, but off course it's not given that I'm getting a segmentation fault. I already managed to understand how a pointer to a pointer works just fine, but I think I'm having trouble putting my head over how the pointer to a pointer to a pointer concept translates into code.
So what am I missing?
You forgot a dereference and got the precedence of * vs. [] wrong:
populate_items(char ***items) {
int i;
*items = (char **) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(*items+i) = (char *) malloc(sizeof(char) * 10);
(*items)[0] = "1234567890";
(*items)[1] = "2345678901";
(*items)[2] = "3456789012";
}
Note, however, that the assignments
(*items)[0] = "1234567890";
etc. lose the only handle to the just allocated memory.
you can use as below
#include "stdafx.h"
#include <stdlib.h>
#include <stdio.h>
char*** populate_items(char ***items)
{
int i;
items = (char ***) malloc(sizeof(char*) * 3);
for (i=0; i<3; i++)
*(items + i) = (char **) malloc(sizeof(char) * 10);
**(items + 0) = "1234567890";
**(items + 1) = "2345678901";
**(items + 2) = "3456789012";
return items;
}
int main(int argv, char *argc)
{
char **items;
int i;
char *** res = populate_items(&items);
for(i=0; i<3; i++)
printf("%s\n", **(res + i));
return 0;
}
Related
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>.
char ** magazine;
char ** ransom;
*magazine = malloc(sizeof(char*) * m);
for(int magazine_i = 0; magazine_i < m; magazine_i++){
magazine[magazine_i] = (char *)malloc(10240 * sizeof(char));
scanf("%s",magazine[magazine_i]);
}
*ransom = malloc(sizeof(char*) * n);
for(int ransom_i = 0; ransom_i < n; ransom_i++){
ransom[ransom_i] = (char *)malloc(10240 * sizeof(char));
scanf("%s",ransom[ransom_i]);
}
Now I want to compare the string stored in ransom to magazine. How it can be done? Please help
You can use strcmp in a loop:
for (i = 0; i < n; i++) {
if (strcmp(magazine[i], ransom[i]) == 0) {
...
}
}
But if (as the title suggests) ransom is declared as a pointer to pointer to char:
char **ransom;
you don't want the dereference operator *
*ransom = malloc(sizeof(char*) * n);
should be
ransom = malloc(sizeof(char*) * n);
I implemented a generic quick sort and now I want to accept the array from command line. Following is a function that is supposed to copy character pointers from array argv to base. I am getting segmentation fault. The copy is working fine when I pass address of two integers.
#include<stdio.h>
void copy(void *src, void *dest, int size)
{
char *s, *d;
int i;
s = src;
d = dest;
for(i = 0; i < size; i++)
d[i] = s[i];
}
int main(int argc, char *argv[])
{
void *base;
int i = 10;
int j = 20;
printf("%d, %d\n", i, j);
copy(&i, &j, sizeof(int));
printf("%d, %d\n", i, j);
copy(argv, base, sizeof(char *));
return 0;
}
Output
10, 20
10, 10
Segmentation fault (core dumped)
argv is a pointer array. If you just want to copy the pointers you can do it like that:
base = calloc( argc, sizeof(char *) );
copy( argv, base, argc * sizeof(char *) );
Now you have copy of the pointer array argv, but that still contains pointers to the original arguments argv[i].
If you want to create copies of argv[i] too, dont use copy() but:
char **base = calloc( argc, sizeof(char *) );
int i;
for( i=0; i<argc; i++ )
base[i] = strdup( argv[i] );
But remember: argv[0] is the program's name and I would bet you don't want that to be part of the array. To avoid it:
base = calloc( argc-1, sizeof(char *) );
copy( argv+1, base, (argc-1) * sizeof(char *) );
or
char **base = calloc( argc, sizeof(char *) );
int i;
for( i=1; i<argc; i++ )
base[i-1] = strdup( argv[i] );
You are trying to copy sizeof(char*) bytes to where base is pointing to. But you did not allocate any memory to base so the program invokes undefined behaviour.
void *base = malloc(strlen(argv[0])+1);
then
copy(argv[0], base, strlen(argv[0])+1);
at the end
free(base);
sizeof(char*) will return a size of a single pointer, not the whole path
Edit:
void *base;
int i;
if (argc>0)
{
base = malloc(argc+1);// we have enough pointers for copying args (+1 to null terminat it)
for(i=0; i < argc; i++)
{
base[i] = malloc(strlen(argv[i])+1);
copy(argv[i], base[i], strlen(argv[i])+1);
}
base[i] = NULL;
}
base will be a double pointer holding all arguments
you may do
memset(...)
and
memcopy(...) btw
Argv is not a single pointer, its a double pointer,
you should be doing like this:
base = calloc(1, sizeof(char *));
copy(argv[1], base, sizeof(char *));
if you really want to copy the full argv, you have to replace
the sizeof(char *) with strlen(argv[0]) and have to allocate base with the length of the argv[0].
My code compiles just fine, but I'm still a little rough on the pointer and array concepts. I would appreciate your help very much.
void initialize(int individual_count, int family_count, char ***indiIDs,
char ***names, char ***spousesIDs, char ***childIDs)
//so here I declared two int variables and four triple pointers,
// which are pointer to a pointer to a pointer to an integer, correct?
{
int i;
//malloc allocates memory space and returns the address of the
// first byte to the pointer *indiIDs,right?
(*indiIDs) = (char**)malloc(sizeof(char*) * individual_count);
(*names) = (char**)malloc(sizeof(char*) * individual_count);
for(i = 0; i <individual_count; i++)
{
(*indiIDs)[i] = (char*)malloc(sizeof(char) * 20);
(*names)[i] = NULL;
}
//*indiIDs[i] is an array of pointers, correct? so what exactly
// is the difference between mallocing and returning to *indiIDs
// and then to *indiIDs[i] as seen here?
(*spousesIDs) = (char**)malloc(sizeof(char*) * family_count);
(*childIDs) = (char**)malloc(sizeof(char*) * family_count);
for(i = 0; i < family_count; i++)
{
(*spousesIDs)[i] = (char*)malloc(sizeof(char) * 40);
//since spousesIDs[][] is a 2D array, would *spousesIDs[][]
// indicate a triple array then?
(*spousesIDs)[i][0] = '\0';
(*childIDs)[i] = NULL;
}
}
Your example doesn't show a 3D array, but a 2D array:
void init2D(char * ** x, int w, int h)
{
(*x) = (char**)malloc(sizeof(char*) * w);
for (i=0; i<w; i++) (*x)[i] = (char*)malloc(sizeof(char) * h);
}
The reason it has an additional * as a function parameter, is because C doesn't have pass-by-refence like C++
It's used this way:
void main ()
{
char ** lines = 0;
init2D (&lines, 4, 256); // char[256] x 4
}
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.