I’m dreading K&R chapter five about pointers and arrays right now. The book initialized an array of char pointers like this :
char *name[] = { “January“, “aFebruary”};So I thought I can do something like :
int *v[] = { {1, 3, 5, 7, 9}, {2, 4, 6, 8}};But the compiler gives a warning in the lines of
initialization of ‘int *’ from ‘int’ makes pointer from integer without a cast
Videos
Here:
list_node_t **array[10] = {NULL};
You're declaring an array of 10 pointers to pointers to your struct. What you want is an array of 10 pointers to your struct:
list_node_t *array[10] = {NULL};
It's confusing because yes, array really is a pointer to a pointer, but the square bracket notation sort of abstracts that away for you in C, and so you should think of array as just an array of pointers.
You also don't need to use the dereference operator on this line:
*array[0] = (list_node_t*) malloc(sizeof(list_node_t));
Because C dereferences it for you with its bracket notation. So it should be:
array[0] = (list_node_t*) malloc(sizeof(list_node_t));
The line list_node_t **array[10] = {NULL}; is wrong - here you declare array of pointers to pointers to list nodes. Replace that with:
list_node_t *array[10] = { NULL };
and it should work.
Suppose you have an array of int of length 5 e.g.
int x[5];
Then you can do a = &x;
int x[5] = {1};
int (*a)[5] = &x;
To access elements of array you: (*a)[i] (== (*(&x))[i]== (*&x)[i] == x[i]) parenthesis needed because precedence of [] operator is higher then *. (one common mistake can be doing *a[i] to access elements of array).
Understand what you asked in question is an compilation time error:
int (*a)[3] = {11, 2, 3, 5, 6};
It is not correct and a type mismatch too, because {11,2,3,5,6} can be assigned to int a[5]; and you are assigning to int (*a)[3].
Additionally,
You can do something like for one dimensional:
int *why = (int p[2]) {1,2};
Similarly, for two dimensional try this(thanks @caf):
int (*a)[5] = (int p[][5]){ { 1, 2, 3, 4, 5 } , { 6, 7, 8, 9, 10 } };
{11,2,3,5,6} is an initializer list, it is not an array, so you can't point at it. An array pointer needs to point at an array, that has a valid memory location. If the array is a named variable or just a chunk of allocated memory doesn't matter.
It all boils down to the type of array you need. There are various ways to declare arrays in C, depending on purpose:
// plain array, fixed size, can be allocated in any scope
int array[5] = {11,2,3,5,6};
int (*a)[5] = &array;
// compound literal, fixed size, can be allocated in any scope
int (*b)[5] = &(int[5]){11,2,3,5,6};
// dynamically allocated array, variable size possible
int (*c)[n] = malloc( sizeof(int[n]) );
// variable-length array, variable size
int n = 5;
int vla[n];
memcpy( vla, something, sizeof(int[n]) ); // always initialized in run-time
int (*d)[n] = &vla;
The malloc calls in the first few examples allocate a block of memory and assign a pointer to that memory to arr. As soon as you assign to arr again, the pointer value is overwritten, and you've lost track of that allocated memory -- i.e., you've leaked it. That's a bug right there.
In other words, if you allocate a block of memory using using malloc(), then you can write data into it using array syntax (for example):
int* arr = (int *) malloc(sizeof(int) * 5);
for (int i=0; i<5; ++i)
arr[i] = i;
But you can't assign anything else directly to arr, or you lose the pointer to that block of memory. And when you allocate a block using malloc(), don't forget to delete it using free() when you don't need it anymore.
An array is not a pointer-to-integer; it's an array. An array name is said to "decay to a pointer" when you pass it as an argument to a function accepting a pointer as an argument, but they're not the same thing.
Regarding your last question: that's actually the difference between an array and a pointer-to-type: the compiler knows the size of an array, but it does not know the size of a block pointed to by an arbitrary pointer-to-type. The answer, unfortunately, is no.
But since you're writing C++, not C, you shouldn't use arrays anyway: use `std::vector'! They know their own length, plus they're expandable.
When you say: ptr = {1,2,3,4,5}, you make ptr point to a memory in the data segment, where constant array {1,2,3,4,5} resides and thus you are leaking memory. If you want to initialize your memory, just after allocation, write: ptr[0]=1; ptr[1]=2; and so on. If you want to copy data, use memcpy.
int * array[10];
defines 10 pointers on 10 int arrays statically
To go dynamic:
int **array = new int *[10];
Better solution since you use C++: use std::vector
std::vector<int *> v;
v.resize(10);
v[2] = new int[50]; // allocate one array
Since we're using vectors for the array of pointers, lets get rid of the pointers completelely
std::vector<std::vector<int> > v;
v.resize(10);
v[2].resize(50); // allocate one array
Then access the array like a matrix:
v[3][40] = 14;
Going further, one way to initialize all the rows, using C++11, making a 10x50 int matrix in the end (but size can also change within the loop if we want). Needs gcc 4.9 and g++ -std=c++11 to build
std::vector<std::vector<int> > v;
v.resize(10);
for (auto &it : v)
{
it.resize(50); // allocate arrays of 50 ints
}
In general in most cases there is no great sense to initialize the array with exact addresses. You could assign the addresses or allocate appropriate memory during the usage of the array.
Usually there is sense to initialize an array of pointers with null pointers. For example
int * array[10] = {};
If you want to declare the array and at once to allocate memory for each element of the array you could write for example
int * array[10] =
{
new int, new int, new int, new int, new int, new int, new int, new int, new int, new int
};
or
int * array[10] =
{
new int( 0 ), new int( 1 ), new int( 2 ), new int( 3 ), new int( 4 ), new int( 5 ), new int( 6 ), new int( 7 ), new int( 8 ), new int( 9 )
};
But in any case it would be better to do the assignment using some loop or standard algorithm because in general the array can have more than 10 elements.
Also you should not forget to delete all allocated memory. For example
std::for_each( std::begin( array ), std::end(array ), std::default_delete<int>() );
Or if you have already defined objects of type int you could write for example
int x0, x1, x2, x3, x4, x5, x6, x7, x8, x9;
//...
int * array[10] =
{
&x0, &x1, &x2, &x3, &x4, &x5, &x6, &x7, &x8, &x9
};
Such an initialization is used very often for arrays of function pointers.
You need to allocate enough memory for 16 pointers, not just one.
arr = (char **)calloc(16, sizeof(char*));
What happens with your code is that arr has enough memory only for one pointer, so arr[0] = <something> is correct, but arr[1] and higher is touching memory that doesn't belong to the program.
Additionally, the way you assign the string pointers is wrong. You are assigning 0 or 1 values, depending on whether the result if calloc is NULL. You need to add parentheses there:
if ((arr[i] = (char *)calloc(1, 2*sizeof(char))) == NULL)
perror("Memory cannot be allocated to arr[%d]", i);
Er even better:
for(i = 0; i < 16; i++) {
arr[i] = (char *)calloc(1, 2*sizeof(char));
if (arr[i] == NULL) {
perror("Memory cannot be allocated to arr[%d]", i);
}
}
When you use calloc, it is customary to use the first parameter to pass the number of elements in the array and the second parameter to pass the size of an element. So, to allocate an array of 16 pointers, one'd normally use calloc(16, <pointer size>), not calloc(1, 16 * <pointer size>), although both do the same thing. In your code you apparently completely forgot about 16 and allocated only 1 pointer.
Don't cast the result of 'calloc'.
Avoid using sizeof(<type>) when calculating size for memory allocation functions. Prefer to use sizeof *<pointer> instead.
If you want to store srings of length 2, you need a buffer of at least 3 characters long (an extra character for zero-terminator).
Memory allocation failure doesn't normally set errno, so perror is not an appropriate function to use here.
Yor assignment to arr[i] in if condition is missing braces. The operations are associated incorrectly. It won't compile as is.
char **arr;
arr = calloc(16, sizeof *arr);
for(i = 0; i < 16; i++)
if((arr[i] = calloc(3, sizeof *arr[i]) == NULL)
fprintf(stderr, "Memory cannot be allocated");
Finally, an unnamed "magic constant" (16 and 3) is most of the time not a good idea.
If the function you want to supply as the default contents of the array is called func, then
- you better use a
typedef, - you have to use an array initializer
Consider:
typedef int (*IntFunc)(void);
IntFunc fparr[5] = { func, func, func, func, func };
Or the less readable way, if you prefer to avoid typedef:
int (*fparr[5])(void) = { func, func, func, func, func };
Because you are not actually initialising an array of function pointers ... try:
int (*fparr[5])(void) = { func1, func2, func3, func4, func5 };