Allocating memory for pointer to pointer to pointer in C - c

I am trying to allocate memory for triple pointer and I cannot make it right. I have pointer to pointer to char
char **words;
allocate(&words);
And I created method for memory allocation:
void allocate(char ***words){
for (int i = 0; i < MAXWORDNUM; ++i)
(*words)[i] = malloc(sizeof(char*) * MAXWORDNUM);
for (int i = 0; i < MAXWORD; ++i)
(**words)[i] = malloc(sizeof(char) * MAXWORD);
}
As I understand I should allocate memory for pointers and then I should allocate memory for each char. For the above code I am getting error:
warning: incompatible pointer to integer conversion assigning
to 'char' from 'void *' [-Wint-conversion]
(**words)[i] = malloc(sizeof(char) * MAXWORD);
How to make it work?
Thank you

void allocate(char ***words){
*words = malloc(sizeof(char*) * MAXWORDNUM);
for (int i = 0; i < MAXWORDNUM; ++i)
(*words)[i] = malloc(MAXWORD);
}

You want an array of pointers, not an array of array of pointers, the first loop is not needed:
void allocate(char ***words){
/* for (int i = 0; i < MAXWORDNUM; ++i) */
/* (m)allocate space for n pointers to words */
*words = malloc(sizeof(char *) * MAXWORDNUM);
for (int i = 0; i < MAXWORDNUM; ++i)
(*words)[i] = malloc(MAXWORD); /* (m)allocate space for each word */
}
int main(void)
{
char **words;
allocate(&words);
return 0;
}

It depends on your purpose, do you intend to create a 2-dimensional array, or a array of pointers, or just a pointer to pointer?
1) A 2-dimensional array
void allocate_two_dimen_array(char ***words, unsigned int x, unsigned int y){
*word = malloc(x * y * sizeof(char));
}
2) A array of char pointers
void allocate_pointer_array(char ***words, unsigned int quantity){
*word = malloc(quantity * sizeof(char*));
}
3) A pure pointer to char pointer
void allocate_pointer_pointer(char ***words){
*word = malloc(sizeof(char**));
}
For practical purposes, for instance: the first one can be used to store a bmp image, the second one is used to store a set of strings
word = {"This is the first line", "This is the second line"};

Related

My program crashes when using realloc in C

#include <stdio.h>
#include <stdlib.h>
char **Names;
int size = 2; //Minimum size for 2D array
void main() {
int i;
Names = (char **)malloc(size * sizeof(char *)); // First initaliaion of 2D array in heap
for (i = 0; i < size; i++)
Names[i] = (char *)malloc(20 * sizeof(char));
printf("\nenter");
for (i = 0; i < size; i++)
scanf("%s", Names[i]);
while (1) {
size++;
Names = (char **)realloc(Names, size * sizeof(char *)); //Dynamic allocation of 2D aray
for (i = 0; i < size; i++)
Names[i] = (char *)realloc(Names[i], 20 * sizeof(char));
i = size - 1;
printf("\nenter");
scanf("%s", Names[i]);
for (i = 0; i < size; i++)
printf("\n%s", Names[i]);
}
}
It doesn't crash immediately it depends on the "size" I initialized.
It crashes after 5 allocations for me.
I tried adding free function but it did not seem to help.
After this memory reallocation
size ++;
Names= (char**)realloc(Names,size*sizeof(char *));
the last pointer pf the array of pointers has an indeterminate value because it was not initialized.
As a result the call of realloc for the last pointer in this loop
for (i=0; i<size; i++)
Names[i] = (char*)realloc(Names[i],20*sizeof(char));
invokes undefined behavior.
Before executing the loop you need to initialize the last pointer at least like
Names[size-1] = NULL;
In fact there is no sense to use the for loop because what you need is to allocate memory for the newly added pointer. The allocated memory pointed to by the early created pointers is not being changed in size.
So instead of
for (i=0; i<size; i++)
Names[i] = (char*)realloc(Names[i],20*sizeof(char));
you could just write
Names[size-1] = malloc( 20 * sizeof( char ) );
Pay attention to as you have an infinite loop then the memory reallocation sooner or later can fail.
Also according to the C Standard the function main without parameters shall be declared like
int main( void )

Expand a C array inside a function

This works in a main, but breaks when put into a function. I'm not sure how to reassign the pointer after passing into a function.
void expandArray(int** arr[], int* size) {
int *temp;
*temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
arr[i] = temp[i];
printf("to arr: %d \n", arr[i]);
}
*size = *size * 2;
free(temp);
}
main(){
int *arr;
arr = (int*) malloc(maxSize * sizeof(int));
if ....
expandArray(arr, &arrSize);
// use bigger arr for other stuff
}
In main, arr is declared as int *arr. When main calls expandArray, it should pass a pointer to arr, which is written &arr and has type int **a.
However, you declared the parameter to expandArray as int **arr[], adding additional brackets. Those are unnecessary and change the type, and your compiler should have warned you about that. Pay attention to compiler warnings. Be sure you understand them, and resolve them before proceeding.
In expandArray, you use both arr[i] and temp[i] to access the array. However, arr[i] is not a correct way to access array elements. When the declaration of the arr parameter is corrected, it will be int **arr, and it will not be proper to refer to an element of the array as arr[i]. It will be (*arr)[i].
Commonly, to make this a little less confusion, authors will use a temporary variable to hold the pointer, so they do not need the extra asterisk:
int *NewArray = malloc(...); // Get new space.
*arr = NewArray; // Send new address to caller.
...
NewArray[i] = temp[i]; // Use temporary variable for access.
Some other points:
When calling malloc, use sizeof *p, where p is the pointer being assigned to, rather than sizeof(int). This is better because, if you later want to change the type for p, it only has to be changed in its declaration, not also in the sizeof. Then there is less likely to be a mistake where it is changed in one place and not another.
Do not cast the result of malloc. This is unnecessary in C, although it is required in C++.
main should be declared as int main(void) or int main(int argc, char *argv[]), not as main(). (C implementations may also provide for other forms.)
Use size_t for sizes of arrays, not int, and either size_t or ptrdiff_t for indices of arrays.
Overall, the code could be:
#include <stdio.h>
#include <stdlib.h>
void expandArray(int **arr, int *size)
{
// Record old pointer and size in temporary variables for convenience.
int *OldArray = arr;
size_t OldSize = *size;
// Prepare new size and pointer.
size_t NewSize = 2 * OldSize;
int *NewArray = malloc(NewSize * sizeof *NewArray);
// Handle allocation failure.
if (!NewArray)
{
fprintf(stderr, "Error, unable to allocate memory.\n");
exit(EXIT_FAILURE);
}
// Copy data from old array to new array.
for (size_t i = 0; i < OldSize; ++i)
NewArray[i] = OldArray[i];
// Send new size and pointer to caller.
*size = NewSize;
*arr = NewArray;
// Release old memory.
free(OldArray);
}
int main(void)
{
int *arr;
arr = malloc(InitialSize * sizeof *arr);
if (...)
expandArray(&arr, &arrSize);
// use bigger arr for other stuff
}
I think the arr sould be int ** type.
void expandArray(int** arr, int* size) {
int *temp;
temp = *arr;
*arr = (int*) malloc(*size * 2 * sizeof(int));
for (int i = 0; i < *size; i++) {
printf("assigning from temp: %d ", temp[i]);
(*arr)[i] = temp[i];
printf("to arr: %d \n", (*arr)[i]);
}
*size = *size * 2;
free(temp);
}
If you just want to expand the array size, you can use realloc.
And the extended area should be initialized using memset.
void expandArray(int** arr, int* size) {
*arr = (int*) realloc(*arr, *size * 2 * sizeof(int));
memset(*arr+*size, 0, *size * sizeof(int));
*size = *size * 2;
}

Generic copy using void pointer

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].

C Malloc Multidimensional Char Array

I would like to dynamically allocate (malloc) a multidimensional character array in C. The array would have the following format:
char *array[3][2] = {
{"one","two"},
{"three","four"},
{"five","six"}
};
Before the array would be created, I would already know the number of rows and the lengths of all of the characters arrays in the multidimensional array.
How would I malloc such a character array?
Thanks in advance!
This is one way to allocate a two dimensional array of char *.
Afterwards, you can assign the contents like a[1][2] = "foo";
Note that the elements of the array are initialized to (char *)0.
#include <stdio.h>
#include <stdlib.h>
char ***alloc_array(int x, int y) {
char ***a = calloc(x, sizeof(char **));
for(int i = 0; i != x; i++) {
a[i] = calloc(y, sizeof(char *));
}
return a;
}
int main() {
char ***a = alloc_array(3, 2);
a[2][1] = "foo";
printf("%s\n", a[2][1]);
}
[Charlies-MacBook-Pro:~] crb% cc xx.c
[Charlies-MacBook-Pro:~] crb% a.out
foo
First of all, arrays are typically stored in Row Major form, so in reality you have a vector six elements long, each entry is a char * ptr. That is, the elements labelled by row, column are similar to:
char *r1c1, *r1c2, *r2c1, *r2c2, *r3c1, *r3c1;
Thus, do a SIMPLE malloc of:
char *matrix = malloc(3*2*sizeof(char *));
Then set the elements as:
matrix[0] = "one";
matrix[1] = "two";
matrix[2] = "three";
matrix[3] = "four";
matrix[4] = "five";
matrix[5] = "six";
Finally, to test this write a nested loop as:
for (int r=0; r<3; r++)
{
for (int c=0; c<2; c++);
{
printf("%s\n",matrix[r][c]);
}
}
Note, how a matrix is treated first as a vector then as a matrix. C doesn't care!!
char *array[3][2] is nothing but a two dimensional array of pointers. Hence you need the storage space of 3*2*sizeof(char *) to store the pointers.
As you mentioned, the pointers are actually pointing to zero-terminated strings and you may like the strings to be malloc'ed as well. Assuming the total length of all the strings to be N (including zero-termination), the storage space needed is (3*2*sizeof(char *) + N).
Allocate memory for the above mentioned size and the copy the strings yourselves as below.
In the following code, we assume that the number of columns (2) is a constant
char *(*dst)[2] = (char *(*)[2]) malloc(3*2*sizeof(char *) + N);
char * s = ((char *) dst) + (3*2*sizeof(char *));
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
strcpy(s, src[i][j]);
dst[i][j] = s;
s += strlen(s)+1;
}
}
NOTE: In the above code, 'dst' is a pointer that points to the first row of the 2D array of char *.
If the number of columns is not constant, the syntax changes a bit, but the storage size is the same.
char **dst = (char **) malloc(3*2*sizeof(char *) + N);
char * s = ((char *) dst) + (3*2*sizeof(char *));
for (i = 0; i < 3; i++)
{
for (j = 0; j < 2; j++)
{
strcpy(s, src[i][j]);
dst[i*2 + j] = s; /* 2 is the number of columns */
s += strlen(s)+1;
}
}
NOTE: Here 'dst' is a pointer that points to the first element of 1D array of char * and the 2D indexing is done manually.
The above examples assume that the string lengths will not change after allocation. If the strings can change at any point in time after allocation, then it is better to allocate for each string separately.
Keep it simple, Sheldon. The answer you've selected uses a char ***, which is not even close to the equivalent of a char *[2][3]. The difference is in the number of allocations... An array only ever requires one.
For example, here's how I'd retro-fit the answer you selected. Notice how much simpler it is?
#include <stdio.h>
#include <stdlib.h>
void *alloc_array(size_t x, size_t y) {
char *(*a)[y] = calloc(x, sizeof *a);
return a;
}
int main() {
char *(*a)[2] = alloc_array(3, 2);
a[2][1] = "foo";
printf("%s\n", a[2][1]);
}
In case you arrive in this page, wanting to create an array like int myarray[n][M] (which is slighly different from the question since they want an array of string), where M is fixed and n can vary (for example if you want an array of coordinates...), then you can just do:
int (*p)[M] = malloc(n*sizeof *p);
and then use p[i][j] as before. Then, you will get sizeof p[i] = M*sizeof(int):
#include <stdio.h>
#include <stdlib.h>
#define M 6
int main(int argc, char *argv[])
{
int n = 4;
int (*p)[M] = malloc(n*sizeof *p);
printf("Size of int: %lu\n", sizeof(int));
printf("n = %d, M = %d\n", n, M);
printf("Size of p: %lu (=8 because pointer in 64bits = 8 bytes)\n", sizeof p);
printf("Size of *p: %lu (=M*sizeof(int) because each case is an array of length M)\n", sizeof *p);
printf("Size of p[0]: %lu (=M*sizeof(int) because each case is an array of length M)\n", sizeof p[0]);
// Assign
for (int i=0; i<n; i++) {
for (int j=0; j<M; j++) {
(p[i])[j] = i*10+j;
}
}
// Display
for (int i=0; i<n; i++) {
for (int j=0; j<M; j++) {
printf("%2d; ", (p[i])[j]);
}
printf("\n");
}
return 0;
}
which gives:
Size of int: 4
n = 4, M = 6
Size of p: 8 (=8 because pointer in 64bits = 8 bytes)
Size of *p: 24 (=M*sizeof(int) because each case is an array of length M)
Size of p[0]: 24 (=M*sizeof(int) because each case is an array of length M)
0; 1; 2; 3; 4; 5;
10; 11; 12; 13; 14; 15;
20; 21; 22; 23; 24; 25;
30; 31; 32; 33; 34; 35;

triple pointers, arrays, and malloc

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
}

Resources