I defined the three dimensional array like this, but I it can't read any string in it? Where is the problem? Thanks!
int stuTotal, courseTotal,i,k;//a dynamic array
printf("Input the total number of students that you would like to import:");
scanf("%d", &stuTotal);
printf("Input the total number of courses that you would like to import:");
scanf("%d", &courseTotal);
char ***data = (char***)calloc(stuTotal,sizeof(char));//data
for(i = 0;i < stuTotal;i++){
data[i] = (char**)calloc(courseTotal,sizeof(char));
for (k = 0;k < courseTotal;k++){
data[i][k] = (char*)calloc(20,sizeof(char));
}
}
strcpy(data[0][0],"hello");
data[0][0] is shown to be empty.
Your arguments to sizeof are incorrect when you allocate the outer arrays - instead of
char ***data = (char***)calloc(stuTotal,sizeof(char));
it needs to be
char ***data = (char***)calloc(stuTotal,sizeof(char **)); // you're allocating N elements of type `char **`.
You can greatly simplify that call as follows:
char ***data = calloc( stuTotal, sizeof *data ); // sizeof *data == sizeof (char **)
and similarly
data[i] = calloc( courseTotal, sizeof *data[i] ); // sizeof *data[i] == sizeof (char *)
You should not need to cast the result of malloc and calloc unless you're working in C++ (in which case you should be using new or, better yet, some kind of container type) or an ancient C implementation (pre-1989).
You should be using sizeof(char**) for 3d "data" array as every element of this 3d array is char**.
int stuTotal, courseTotal,i,k;//a dynamic array
printf("Input the total number of students that you would like to import:");
scanf("%d", &stuTotal);
printf("Input the total number of courses that you would like to import:");
scanf("%d", &courseTotal);
char ***data = (char***)calloc(stuTotal,sizeof(char**));//data
for(i = 0;i < stuTotal;i++){
data[i] = (char**)calloc(courseTotal,sizeof(char*));
for (k = 0;k < courseTotal;k++){
data[i][k] = (char*)calloc(20,sizeof(char));
}
}
strcpy(data[0][0],"hello");
You specified invalid sizes of allocated objects.
You have to write
char ***data = (char***)calloc(stuTotal,sizeof(char **));//data
^^^^^^^
for(i = 0;i < stuTotal;i++){
data[i] = (char**)calloc(courseTotal,sizeof(char *));
^^^^^^
for (k = 0;k < courseTotal;k++){
data[i][k] = (char*)calloc(20,sizeof(char));
}
}
If your compiler supports variable length array then you can allocate the required array with calling malloc or calloc only once. For example
char ( *data )[courseTotal][20] =
malloc( sizeof( char[stuTotal][courseTotal][20] ) );
or
char ( *data )[courseTotal][courceName] =
calloc( 1, sizeof( char[stuTotal][courseTotal][courceName] ) );
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
size_t stuTotal = 5, courseTotal = 10, courceName = 20;
char ( *data )[courseTotal][courceName] =
calloc( 1, sizeof( char[stuTotal][courseTotal][courceName] ) );
strcpy(data[0][0],"hello");
puts( data[0][0] );
free( data );
return 0;
}
Its output is
hello
In this case to free all the allocated memory it is needed to call free only once.
Related
This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 3 months ago.
I've just started learning malloc() and realloc() and when testing them, I came across this issue with reallocating the size of an int array.
the program is supposed to make an array, initially of size two, but it's supposed to increase its size and add values to it ten times. However it doesn't increase its size and the output ends up being array = {0,1} when it should be array = {0,1,2,3,4,5,6,7,8,9}
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *array= malloc(sizeof(int)*2);
for (int x = 0; x < 10; x++) {
array = realloc(array, sizeof(int)*(2+x));
array[x] = x;
}
for (int i = 0; i<(sizeof(array)/sizeof(array[0])); i++) {
printf("%d\n",array[i]);
}
free(array);
}
could someone explain why it doesn't work?? I've tried looking for answers but none of this makes sense to me lol.
The expression
sizeof(array)/sizeof(array[0])
is equivalent to
sizeof( int * )/sizeof( int )
and yields either 2 or 1 depending on the used system.
Also the expression (2+x) in this statement
array = realloc(array, sizeof(int)*(2+x));
used in each iteration of the for loop does not make sense.
It seems you mean something like the following
enum { N = 10 };
size_t n = 2;
int *array = malloc( n * sizeof( int ) );
for ( int x = 0; x < N; x++ ) {
if ( n <= x )
{
n += 2;
array = realloc( array, n * sizeof( int ) );
}
array[x] = x;
}
for ( int i = 0; i < N; i++ ) {
printf("%d\n",array[i]);
}
free(array);
In general it is safer to use an intermediate pointer in the call pf realloc like for example
int *tmp = realloc( array, n * sizeof( int ) );
if ( tmp != NULL ) array = tmp;
Otherwise you can loose the allocated memory if the call of realloc will return a null pointer.
The problem is that sizeof(array) will just return the size of the pointer (8 bytes on a 64-bit system). You need to track the array size in another variable. For example...
#include <stdlib.h>
#include <stdio.h>
int main(void) {
int *array= malloc(sizeof(int));
int size;
for (size = 0; size < 10; size++) {
array = realloc(array, sizeof(int)*(1+size));
array[size] = size;
}
for (int i = 0; i<size; i++) {
printf("%d\n",array[i]);
}
printf("array size: %ld\n",size*sizeof(int));
free(array);
}
If I have int **array and want to place a series of numbers in it (I don't know its size), 5 3 4 0 or 9 1 5 8 3 0 as an example. As far as I know I should be using malloc
So I did something like this
int **array;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
array = (int**)malloc(sizeof(int*)*(inp+1)); //since inp start at 0
array[inp] = &n; //is this even correct?
inp++;
}
My first question is: Will this method (the loop) upgrade/expand the size of the array or is what I am doing a waste of memory?
The second question is how can I print/edit the values of this array?
EDIT:
From your answers I have came up with the following.
int **array;
int n = 1, inp = 0;
array = (int**)malloc(sizeof(int*));
while(n){
scanf("%d", &n);
realloc( array, sizeof((int*)(inp+1)));
array[inp] = n;
inp++;
}
Is this the correct way to do it?
Note* I am aware that it does not have to be a pointer of a pointer, but I need it to be for something else later on.
You code is wrong for at least these reasons.
1) You keep doing malloc to array and thereby loose previously malloced blocks. The function to use is realloc when extending the size of dynamic memory.
2) You store the address of n instead of the value of n
Besides that it seems strange to use a double pointer. Why not do like:
int *array = NULL;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
array = realloc(array, sizeof(int)*(inp+1));
array[inp] = n;
inp++;
}
EDIT after OPs update
If you really want to use a double pointer (i.e. int **array;), you need to allocate memory in two levels.
That could look like:
int **array = malloc(sizeof *array);
*array = NULL;
int n = 1, inp = 0;
while(n){ // scan till the input is 0
scanf("%d", &n);
*array = realloc(*array, sizeof(int)*(inp+1));
(*array)[inp] = n;
inp++;
}
What you're doing in your code is allocating progressively larger areas of memory and saving the input value in the last position of each new area, while losing the pointers to the previously allocated areas. A commom and efficient solution for what you want (which is used in C++'s vectors, I believe) is to allocate some minimum amount of space, then check at each iteration if you are on the verge of exceeding it. In case you are, reallocate the area doubling the space. Something like this:
int i = 0; //iterator
int s = 1; //array size
int n; //input (use do-while so you don't have to worry about initial value)
//it doesn't have to be bidimensional for a single series
int * array = (int *) malloc(sizeof(int) * s);
do
{
if(i == s)
{
s *= 2;
array = (int *) realloc(array, sizeof(int) * s);
}
scanf("%d", &n);
array[i++] = n; //assign with the value, not with the address
}
while(n)
UPDATE: if you really need to use **int, do it like this:
int n, i = 0, s = 1;
int ** array = (int **) malloc(sizeof(int*) * s);
do
{
if(i == s)
{
s *= 2;
array = (int **) realloc(array, sizeof(int *) * s);
}
scanf("%d", &n);
array[i] = (int *) malloc(sizeof(int));
array[i][0] = n;
++i;
}
while(n)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
int **arr = (int **)malloc(r * sizeof(int *));
how should i interpret the meaning of the above C code ?
The call to malloc() in:
int **arr = (int **)malloc(r * sizeof(int *));
allocates space for r pointers to int, and returns a void * pointing to the allocation. This pointer is then cast to int ** and assigned to arr, which is a pointer to a pointer to int. Thus arr points to the first element of the allocated region, which is a pointer to int. Such code may be used in creating a "jagged" array, where each row of the array is allocated separately; this means that the allocations may not be contiguous in memory, so this would not be a true 2d array. See Correctly allocating multi-dimensional arrays to read more about this.
The above is considered bad style, though. Most importantly, using explicit types as arguments of the sizeof operator should be avoided when possible:
int **arr = (int **)malloc(r * sizeof *arr);
This is less error-prone, and easier to maintain if the type of arr changes at some point in the life of the code.
Further, there is no need to cast the result of malloc() in C, so this cast is superfluous and only serves to clutter the code:
int **arr = malloc(r * sizeof *arr);
As a final refinement, I prefer to place the sizeof expression first in such cases:
int **arr = malloc(sizeof *arr * r);
This is a useless change in the particular case above, but when there is an additional multiplication, e.g.:
int **arr = malloc(sizeof *arr * r * n);
this guarantees that the arithmetic is carried out with a type at least as wide as size_t, reducing the risk of integer overflow (signed integer overflow causes undefined behavior in C), and may reduce the risk of unsigned integer wrap-around (well-defined, but possibly unexpected or unwelcome).
This
int **arr = (int **)malloc(r * sizeof(int *));
is a dynamic allocation of an array of the type int * [r] that is an array of r elements that have the type int *.
To make the declaration more clear consider the following simple program
#include <stdio.h>
int main(void)
{
char * s[] = { "Hello", " ", "user292174" };
const size_t N = sizeof( s ) / sizeof( *s );
char **p = s;
for ( size_t i = 0; i < N; i++ ) printf( "%s", p[i] );
putchar( '\n' );
return 0;
}
Its output is
Hello user292174
Here in the program instead of the type int there is used type char for simplicity.
Array designators in expressions with rare exceptions are converted to pointers to their first elements.
So as the type of the array s is char * then a pointer to first element of the array s will have the type char **.
In the case of the original declaration from the question then there is allocated dynamically an extent of memory that is interpreted as an array of elements of the type int *. And the starting address of the extent where the first lement of the implyed array will be exist is assigned to the pointer. So the pointer shall have the type int **.
int **arr = (int **)malloc(r * sizeof(int *));
Usually such allocations are used to simulate a two-dimensional array when the number of rows and columns of the array are calculated at run-time.
For example
#include <stdio.h>
#include<stdlib.h>
int main(void)
{
size_t r = 2;
size_t c = 3;
int **arr = (int **)malloc( r * sizeof( int * ) );
for ( size_t i = 0; i < r; i++ )
{
arr[i] = malloc( c * sizeof( int ) );
}
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
arr[i][j] = c * i + j;
}
}
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
printf( "%d ", arr[i][j] );
}
putchar( '\n' );
}
for ( size_t i = 0; i < r; i++ )
{
free( arr[i] );
}
free( arr );
return 0;
}
The program output is
0 1 2
3 4 5
If the compiler supports variable length arrays then a two dimensional array can be allocated at once. For example
#include <stdio.h>
#include<stdlib.h>
int main(void)
{
size_t r = 2;
size_t c = 3;
int ( *arr )[c] = (int **)malloc( sizeof( int[r][c] ) );
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
arr[i][j] = c * i + j;
}
}
for ( size_t i = 0; i < r; i++ )
{
for ( size_t j = 0; j < c; j++ )
{
printf( "%d ", arr[i][j] );
}
putchar( '\n' );
}
free( arr );
return 0;
}
The porgram output is the same as shown above.
This question already has answers here:
Malloc a 3-Dimensional array in C?
(16 answers)
Closed 8 years ago.
Creating two dimensional arrays in C is easy:
char (*arr)[50] = malloc(sizeof(arr) * 10 * 50); // 10x50 matrix
How do you do three dimensional arrays in C? It doesn't look like I can do something like:
char (**arr)[50] = malloc(sizeof(arr) * 10 * 20 * 50); // 10x20x50 matrix?
Three dimensional array requires 2 dimensions to be known
char (*arr)[20][50] = malloc(sizeof(char) * 10 * 20 * 50)
Note: I have corrected sizeof(arr) to sizeof(char), because sizeof(arr) will return the size of a pointer.
A possible way could be to allocate a mono-dimensional array, e.g.
int width=10; length=20; height=50;
char* arr = malloc(width*length*height);
if (!arr) { perror("malloc"); exit(EXIT_FAILURE); };
then have some way to access it, for instance a macro
#define Element(I,J,K) arr[width*length*(I)+length*(J)+(K)]
and use Element(i,j,k)
You could pack all this using a flexible array member like
struct my3dstring_st {
int width;
int length;
int height;
char arr[];
};
then have a.g. a making function
struct my3dstring_st *
make_my3dstring (int width, int length, int height)
{
if (width<=0 || length<=0 || height<=0) return NULL;
struct my3dstring_st* s =
malloc(sizeof(struct my3dstring_st)
+ width * length * height);
if (!s) {perror("malloc"); exit(EXIT_FAILURE); };
s->width = width;
s->length = length;
s->height = height;
memset (s->arr, 0, width * length * height);
return s;
}
and an inline accessing function (in a header file):
static inline int
access_m3dstring(struct my3dstring_st*s, int i, int j, int k) {
if (!s || i<0 || j<0 || k<0
|| i>=s->width || j>=s->height || k>=s->length) return EOF;
return s->arr[i*->width*s->height + j*s->height + k];
}
I leave as an exercise to write the modification function modify_m3dstring, and you could have unsafe but faster variants which don't do any checks...
General rules:
T *arr = malloc( sizeof *arr * n ); // for an N-element array
T (*arr)[N] = malloc( sizeof *arr * m ); // for an NxM-element array
T (*arr)[N][M] = malloc( sizeof *arr * k ); // for an NxMxK-element array
where uppercase letters indicate values that are known at compile time and lowercase letters indicate values that are known at run time. The pattern for higher-dimensional arrays should be obvious.
If you are using C99 compiler or a C2011 compiler that supports variable-length arrays, you can use runtime variables for all your dimensions:
size_t n = some_value();
size_t m = some_other_value();
size_t k = yet_another_value();
T (*arr)[n][m] = malloc( sizeof *arr * k );
The type of the expression *arr is T [n][m], so sizeof *arr gives the same result as sizeof (T) * n * m; the result is easier to read and less prone to errors.
If your compiler doesn't support VLAs and you don't know your dimensions at compile time, you'll either have to allocate as a 1-d array and compute offsets manually:
T *arr = malloc( sizeof *arr * n * m * k );
...
arr[ 3*n*m + 2*m + 1] = x; // equivalient to arr[3][2][1] = x
Or, if you can live with your rows not being adjacent in memory, you could allocate the array piecemeal:
T ***arr = malloc (sizeof *arr * n );
for (size_t i = 0; i < n; i++ )
{
arr[i] = malloc( sizeof *arr[i] * m );
for (size_t j = 0; j < m; j++ )
{
arr[i][j] = malloc( sizeof *arr[i][j] * k )
}
}
Ideally, you should check the result of each malloc to make sure it succeeded. And you'll have to free the array in the reverse order that you allocated it:
char (*arr)[20][50] = malloc(sizeof(char) * 10 * 20 * 50);
sizeof(char) is guaranteed to be 1. So, it can be omitted.
char (*arr)[20][50] = malloc(10 * 20 * 50);
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;