I don't know where I'm wrong and I get segmentation fault error. Can you help?
My Code;
#include <stdio.h>
#include <stdlib.h>
void do_array(int x, int y, int **arr){
arr=(int **)malloc(sizeof(int)*x);
for (int i=0;i<y;i++){
*(arr+i)=(int *)malloc(sizeof(int)*y);
}
}
int main(){
int **p;
do_array(5,2,p);
for (int i=0;i<5;i++){
for (int j=0;j<2;j++){
*(*(p+i)+j)=i;
}
}
for (int i=0;i<5;i++){
for (int j=0;j<2;j++){
printf("%d\n",*(*(p+i)+j));
}
}
return 0;
}
!!! I want to do is create a dynamic 2D array
The formal argument arr in the function is a separate object from the actual argument p in main - any changes to arr are not applied to p, so p is never set to point to the memory you just allocated.
What you will have to do is pass a pointer to p:
void doArr(int x, int y, int ***arr){
*arr=(int **)malloc(sizeof(int *)*x); // note type of sizeof - you're allocating an array of int *, not int
for (int i=0;i<y;i++){
*(*arr+i)=(int *)malloc(sizeof(int)*y);
}
}
...
doArr( 5, 2, &p );
Or, return arr and assign the result of doArr to p:
int **p = doArr( int x, int y )
{
int **arr = malloc(...);
...
return arr;
}
p = doArr( 5, 2 );
As Emanuel P notes, do is a keyword, so you can't use it as a function name.
A couple of style notes:
Since C89, malloc returns void * and does not require an explicit cast, and many of us will recommend against using it. It just adds visual noise and creates an extra maintenance burden.
Similarly, I often recommend that the operand of sizeof be your target expression, not a type name. Again, this eases your maintenance headaches if you change the type of the destination pointer.
Use array notation instead of pointer arithmetic where possible. It's easier to read and follow, and you're less likely to make a mistake.
Finally, always check the result of a malloc, calloc, or realloc call.
I'd rewrite your doArr function as follows:
void doArr(int x, int y, int ***arr)
{
*arr = malloc( sizeof **arr * x );
if ( *arr )
{
for ( int i = 0; i < y; i++ )
{
(*arr)[i] = malloc( sizeof *(*arr)[i] * y );
}
}
}
and call it as
doArr( 5, 2, &p );
int main(){
int **p /* = NULL */ ; // p is garbage or NULL
do_array(5,2,p); // p is still garbage or NULL
for (int i=0;i<5;i++){
for (int j=0;j<2;j++){
*(*(p+i)+j)=i; // p is still garbage or NULL
I want to do is create a dynamic 2D array
In your code you do not create a 2D array only the array of pointers.
void *doArr(size_t x, size_t y)
{
int (*arr)[x][y] = malloc( sizeof((*arr)[0][0]) * x * y);
return arr;
}
Related
I got this code:
#include <stdio.h>
#include <string.h>
int main(void)
{
int a[3]={1,2,3},
b[3];
int (*p)[3]= &a;
b = p;
for(int i=0;i<3;i++)
printf("%i",b[i]);
}
-I wanted output to be like "123", but I am having problems assigning the b array to what the p is pointing.
ps -
memcpy( b, p, sizeof(b)); does just what i want but i want to do it without the use of that function.
The line
b = p;
has a couple of problems. First of all, array expressions may not be the target of the = operator; you can't assign an entire array in a single operation like that1.
Secondly, the types don't match; p has type int (*)[3], while b has type int [3]. Arrays are not pointers - array expressions "decay" to pointer expressions under most circumstances, but in this case even the pointers would be of incompatible types (b would decay to an expression of type int *, not int (*)[3]).
No, the only ways to copy the contents of one array to the other are to use library functions like memcpy or to use a loop to assign each element individually:
for ( size_t i = 0; i < 3; i++ )
b[i] = (*p)[i]; // or b[i] = a[i]
That's it.
Initialization is different from assignment.
Arrays do not have the assignment operator. You need somehow to copy elements of one array to another array.
Without using the standard function memcpy you can use an ordinary loop as for example
for ( size_t i = 0; i < sizeof( a ) / sizeof( *a ); i++ )
{
b[i] = a[i];
}
Or if to use intermediate pointers you can write
for ( int *p = a, *q = b; p != a + sizeof( a ) / sizeof( *a ); ++p )
{
*q++ = *p;
}
You have a small fixed size array, perfectly suitable for wrapping inside a struct, so you can do this:
#include <stdio.h>
#include <string.h>
struct ia3 {
int data[3];
}
int main(void)
{
struct ia3 a = {{1,2,3}};
struct ia3 b;
struct ia3 *p = &a;
b = *p; // struct assignment
for(int i=0;i<3;i++) {
printf("%i",b.data[i]);
}
}
"...but i want to do it without the use of [memcpy(,,)]."
It is unclear why using memcpy() is not agreeable in this exercise, but it does do the task more efficiently then loop for large array sizes.
If you just want a pointer to the array...
int a[3] = {1,2,3};
//create pointer
int *b = a;//does not copy array a, just points to it
//If an additional array is needed, do this...
int b[3] = {0};
int i = 0;
//to copy, without memcpy(), use this alternative.
for(i=0; i<3; i++) b[i] = a[i];//makes copy of array a
for(i=0;i<3;i++)
printf("%i", b[i]);
code:
int arr[5] = {1,2,3,4,5};
int (*p)[5] = &arr;
printf("p:%p\n",p);
printf("*p:%p\n",*p);
result: p = *p = arr = 0x7ffee517c830 they are all the address of the array
The right way to use p to visit arr[i] is *(*p+i)
The type of pointer p is int(*)[5], so p point to an array which type is int [5]. But we can't say that p point to an invisible shell of arr, p is a variable after all. It stores the address of arr, which is also the address of arr[0], the first element of arr.
I thought *p will get me 1, which is the first element of arr.
The dereference operation means take the value in p as address and get the value from this address. Right?
So p stores the address of arr,which is 0x7ffee517c830 here, and 1 is stored in this address. Isn't **p illegal? The first dereference give us 1, and second dereference will use 1 as address which is illegal.
What I am missing?
The result of *p is an lvalue expression of array type. Using (*p) is exactly the same as using arr in any expression you could now think of.
For example:
&*p means &arr
**p means *arr (which is legal).
(*p)[i] means arr[i].
sizeof *p means sizeof arr.
Arrays are not special in this regard. You can see the same phenomenon with int x; int *q = &x;. Now *q and x have exactly the same meaning.
Regarding your last paragraph, I think you are confusing yourself by imagining pointers as glorified integers. Some people teach pointers this way but IMO it is not a good teaching technique because it causes the exact confusing you are now having.
If you dereference an int(*)[5] you get an int[5] and that's all there is to it. The data type matters in dereferencing. It does not make sense to talk about "dereferencing 0x7ffee517c830". Again this is not peculiar to arrays; if you dereference a char ***, you get a char ** etc.
The only way in which arrays are "different" in this discussion is what happens if you try to do arithmetic on them, or output them, etc. If you supply an int[5] as a printf argument for example, there is implicit conversion to int * pointing at the first of those 5 ints. This conversion also happens when applying the * operator to an int[5], which is why you get an int out of that.
p is declared as a 'pointer to int[5]'.
arr is declared as an 'int[5]`
so the initializer p = &arr; is not really that strange. If you substituted any primitive type for int[5] you wouldn't bat an eye.
*p is another handle on arr. so (*p)[0] = 1.
This really only comes up in wierd cases. It's most natural where you dereference the pointer-to-array using the subscript operator. Here's a contrived example where I want to pass a table as argument.
#include <stdio.h>
int print_row_range(int (*tab) [2], int first, int last)
{
int i;
for(i=first; i<= last; i++)
{
printf("{%d, %d}\n", tab[i][0], tab[i][1]);
}
}
int main(int argc, char *argv[])
{
int arr[3][2] = {{1,2},{3,4},{5,6}};
print_row_range(arr,1,2);
}
This example treats the table as an array of rows.
Dereferencing doesn't give you a value. It gives you an object, which can be used as a value of its type if it can be converted to.
*p, being identical to arr, is an object of an array of 5 ints, so if you want to get an integer from the array, you must dereference it again like (*p)[3].
Consider a bigger example:
int arr[5][5];
int (*p)[5] = arr;
Now you get arr[0] with *p, which itself is an array of 5. Here comes the difference:
*( p+1) == arr[1];
*(*p+1) == arr[0][1];
^ ^^^
Got the point?
One use case is to be able to allocate with malloc an 2D (or more) pointer of arrays with only one malloc:
#include <stdio.h>
#include <stdlib.h>
static int (*foo(size_t n))[42] {
return malloc(sizeof *foo(0) * n);
// return malloc(sizeof(int [n][42]); works too
}
int main(void) {
size_t n = 42;
int (*p)[42] = foo(n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
I think this very funny.
One more with VLA:
#include <stdio.h>
#include <stdlib.h>
static void *foo(size_t elem, size_t n, size_t m) {
return malloc(elem * n * m);
}
int main(void) {
size_t n = 42;
int (*p)[n] = foo(sizeof **p, n, n);
if (!p) {
return 1;
}
printf("p:");
int accu = 0;
for (size_t i = 0; i < n; i++) {
for (size_t j = 0; j < sizeof *p / sizeof **p; j++) {
p[i][j] = accu++;
printf(" %d", p[i][j]);
}
}
printf("\n");
free(p);
}
In main() function I initialize a couple of variables (int and int* array). Then I print something out and read them from the console scanf.
I want to place this functionality into some external function so that the main will look like this:
int main()
{
int n = 0, x = 0;
int *arr = NULL;
load(&n, &x, &arr);
}
After load() function call I want the variables to be exactly as they were set inside of the load() function. How can I do this?
And second question, just out of curiosity:
/**
* Description of the function
*
* #param int n Foo
* #param int x Bar
* #param int *arr Does something
*/
void load(int n, int x, int *arr)
{
// something
}
Is this documentation useful in C coding, and is it a good practice?
You are passing address of two int and one pointer(third argument), you should receive first two arguments in pointer(one *) to int and third argument in pointer to pointer(two **) of int:
void load(int* n, int* x, int **arr){
// ^ ^ one* ^ two **
*n = 10;
*x = 9;
}
In load function you can assign values to *n and *x because both points to valid memory addresses but you can't do **arr = 10 simply because arr doesn't points to any memory (points to NULL) so first you have to first allocate memory for *arr, do like:
void load(int* n, int* x, int **arr){
*n = 10;
*x = 9;
*arr = malloc(sizeof(int));
**arr = 10;
}
Is this documentation useful in C coding, and is it a good practice?
Yes
but Sometimes I documents my function arguments like in following ways:
void load(int n, // is a Foo
int x, // is a Bar
int **arr){ // do some thing
// something
}
A reference: for document practice
Edit As you are commenting, do like below I am writing, it will not give any error/because of malloc().
#include<stdio.h>
#include<stdlib.h>
void load(int* n, int* x, int **arr){
*n = 10;
*x = 9;
*arr = malloc(sizeof(int));
**arr = 10;
printf("\n Enter Three numbers: ");
scanf("%d%d%d",n,x,*arr);
}
int main(){
int n = 0, x = 0;
int *arr = NULL;
load(&n, &x, &arr);
printf("%d %d %d\n", n, x, *arr);
free(arr);
return EXIT_SUCCESS;
}
Compile and run like:
~$ gcc ss.c -Wall
:~$ ./a.out
Enter Three numbers: 12 13 -3
12 13 -3
As Commented by OP:
"Invalid convertion from void* to int*" when I change this to arr = malloc(sizeof(int)(*n));
syntax of malloc():
void *malloc(size_t size);
malloc() returns void* and *arr type is int* that is the reason compiler messages because of different types : "Invalid convertion from void* to int*"
But I avoid casting when malloc(), since: Do I cast the result of malloc? (read Unwind's answer)
Say I have a function called array_push in c.
void array_push(int *array_pointer, int array_length, int val) {
int i;
int *temp_array = malloc(sizeof(int) * (array_length + 1));
for (i = 0; i < array_length; i++) {
temp_array[i] = *array_pointer;
array_pointer++;
}
temp_array[array_length] = val;
*array_pointer = temp_array;
}
How can I update the pointer *array_pointer so that it points to temp_array and other parts of my program can use the new array? Allowing me to do something like
int t[2] = {0,2};
array_push(t, 2);
/* t should now contain {0,2,3} */
You need to turn array_pointer into a pointer-to-pointer:
void array_push(int **array_pointer, int array_length, int val) {
(note the extra asterisk).
Also, you'll need to change the call site so that t is a pointer, not an array (you can't make an array point someplace else). Finally, to make the caller aware of the new size of the array, array_length also needs to be passed by pointer.
Thus, the overall structure of your code could be something like:
void array_push(int **array_pointer, int *array_length, int val) {
int *temp_array = malloc(sizeof(int) * (*array_length + 1));
memcpy(temp_array, *array_pointer, sizeof(int) * *array_length);
temp_array[(*array_length)++] = val;
free(*array_pointer);
*array_pointer = temp_array;
}
int main() {
int n = ...;
int* t = malloc(sizeof(int) * n);
/* ... */
array_push(&t, &n, 2);
/* ... */
free(t);
}
Note how I've allocated t on the heap, and have freed *array_pointer inside array_push(). With this in mind, much of the array_push()'s logic can be simplified by using realloc():
void array_push(int **array_pointer, int *array_length, int val) {
*array_pointer = realloc(*array_pointer, sizeof(int) * (*array_length + 1));
(*array_pointer)[(*array_length)++] = val;
}
There are two problems here: You seem confused about pass-by-value, but the more significant problem is that you seem confused about pointers. int *array_pointer array_pointer points to an int, not an array. It may be that it points to the first int in an array. On an unrelated note, a "pointer to an int array" looks like: int (*array_pointer)[array_length].
Back to the point: int *array_pointer array_pointer points to an int. In *array_pointer = temp_array;, the expression *array_pointer gives you the object pointed to, which can store an int. temp_array isn't an int value, though.
I can see that you're attempting to work around the issue that changes made to array_pointer aren't visible to the caller, due to the semantics of pass-by-value. Hence, you need to change array_pointer so that it points to an int * that the caller supplies, so that you're modifying the caller's int *, or use the return type to return the new pointer. As it turns out, both of these options solve both of your problems.
PROBLEM 1:
If you want to create or modify an *int array inside of a function, then you need to pass a "pointer to a pointer":
// WRONG:
void array_push(int *array_pointer, int array_length, int val) {
...
int *temp_array = malloc(sizeof(int) * (array_length + 1));
...
*array_pointer = temp_array;
Instead:
// BETTER:
void array_push(int **array_pointer, int array_length, int val) {
...
int *temp_array = malloc(sizeof(int) * (array_length + 1));
...
*array_pointer = temp_array;
Or:
// BETTER YET:
int * array_push(int array_length, int val) {
...
int *temp_array = malloc(sizeof(int) * (array_length + 1));
...
return temp_array;
PROBLEM 2:
If you want to declare a static array like this int t[2] = {0,2};, then you can't arbitrarily change it's size. Here's a good description of "arrays vs pointers":
http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1069897882&id=1073086407
One of the first things a new student learns when studying C and C++
is that pointers and arrays are equivalent. This couldn't be further
from the truth...
I've got about 12000 pre known values that I need to place in an array early in the program. Given certain circumstances, I will later need to resize this array with realloc. Is there any way to initialize an array with malloc/calloc with values, or fill an array with several other values?
You cannot initialize a malloced array this way, your best chance is to have it statically in your program, and copy it to a malloced array at the beginning of the run, e.g.:
static int arr[] = {1,2,3,4};
static int * malloced_arr;
// in the init function
malloced_arr = malloc(sizeof(arr));
if (malloced_arr)
{
memcpy(malloced_arr, arr, sizeof(arr));
}
This is the sort of thing that zero length arrays are useful for. For example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct values {
int x[4];
int y[0];
} V = { {1, 2, 3} };
int
main( int argc, char ** argv )
{
int *t;
int i;
struct values *Y;
(void) argc; (void) argv;
/* Allocate space for 100 more items */
Y = malloc( sizeof *Y + 100 * sizeof *Y->y );
t = Y->x;
memcpy( Y, &V, sizeof V );
t[3] = 4;
for( i = 0; i < 4; i++ )
printf( "%d: %d\n", i, t[ i ]);
return 0;
}
Of course, this is really just a parlor trick that gains you nothing over Binyamin's solution, and introduces a lot of totally unnecessary obfuscation.