Classical Array Implementation Using Pointers and Memory Allocation - c

So I got this question from a competition website and I am completely puzzled. Here it is:
Which of the following memory allocation code for p[10][10] confirms perfectly to classical definition of an array? The options are:
char **p;
int i;
p = (char**)malloc(10*sizeof(char*));
*p = (char*)malloc(10*sizeof(char));
for(i = i; i<10; i++)
p[i] = p[0] +10*i;
char **p;
int i;
p = (char**)realloc(p, 10*sizeof(char*));
*p = (char*)realloc(p, 10*sizeof(char));
for(i = i; i<10; i++)
p[i] = p[0] +10*i;
char **p = NULL;
int i;
p = (char**)malloc(10*sizeof(char*));
*p = (char*)malloc(10*sizeof(char));
for(i = i; i<10; i++)
p[i] = (char*)realloc(p[i-1], 10*i*sizeof(char));
char **p;
int i;
p = (char**)malloc(10*sizeof(char*));
for(i = i; i<10; i++)
p[i] = (char*)malloc(10*sizeof(char));
I am completely puzzled. Any ideas are most welcome. Thanks.
EDIT: If none of them are are correct, what would be the correct implementation? A bit of explanation is most welcome as I am preparing for aa competitive exam that requres these skills which ask questions like this (most of which has obvious 'side effects' :( ). Also edited the typos.

None. This one does:
char (*p)[10] = malloc(10*sizeof(*p));
Explanation:
p is declared as a pointer to an array of ten chars. Since it points to an array, sizeof(*p) returns the size of that array, which is 10. So, the malloc() call allocates memory for ten such arrays, i. e. 100 bytes.
Now, when you derefence the pointer as in p[3], the value is the fourth array in the slap of memory. However, this value decays to a pointer to its first element in almost all contexts, so when you say p[3][5] the value is the 6th element within the 4th array within the memory slap.
Sorry, if this sounds a bit confusing, but it's really the same thing that's happening when you declare an array with char array[10][10];, except that the memory comes from a different place.

First things first : do not cast the return value of malloc in C. This is not your code, but anyway, it is always good to say.
Also, the loops should be rewritten like so : for(i = 1; i < 10; i++) or maybe for(i = 0; i < 10; i++). i = i is probably an error (what is that website, again ?), and I will assume so.
char **p;
int i;
p = malloc(10*sizeof(char*));
*p = malloc(10*sizeof(char));
for(i = 1; i < 10; i++)
p[i] = p[0] + 10*i;
This first code allocates 10 char* to p, and then 10 char to *p, which is equivalent to p[0]. Then, it puts the addresses of an unallocated 2D array into the other values of p[i] for i from 1 to 9. Since the array is not allocated (or only partially - p[0] is allocated), this is pretty bad.
char **p;
int i;
p = realloc(p, 10*sizeof(char*));
*p = realloc(p, 10*sizeof(char));
for(i = 1; i < 10; i++)
p[i] = p[0] + 10*i;
This second code uses realloc instead of malloc, which does not solve the previous problems, but also adds probable segmentation faults : realloc on an uninitialized pointer is a bad idea.
char **p = NULL;
int i;
p = malloc(10*sizeof(char*));
*p = malloc(10*sizeof(char));
for(i = 1; i < 10; i++)
p[i] = realloc(p[i-1], 10*i*sizeof(char));
This third code does the same as the first one for the first part, but then uses realloc on p[i] for i starting with 0. I assume realloc deallocates the pointer you pass to it, so this is not really a good idea. And the 10*i*sizeof(char) is not a good idea either. Basically, you will have p[9] allocated with 90 char, and nothing else. And, by the way, initializing p to NULL here doesn't do anything.
char **p;
int i;
p = malloc(10*sizeof(char*));
for(i = 0; i < 10; i++)
p[i] = malloc(10*sizeof(char));
This fourth code has something good at least : it allocates separately each p[i] for i from 0 to 9 (I assume i starts with 0 here, unlike in the other codes). So, this might be the answer you are looking for.
Finally, the question is badly formulated since none of these codes have the same semantics as a declaration like char p[10][10].
Edit :
If you want a dynamically allocated 2D array, you can use this for instance :
int i;
char **p = malloc(10 * sizeof *p);
for(i = 0; i < 10; i++)
p[i] = malloc(10 * sizeof *p[i]);
You can also, as cmaster did, use a pointer to an array type (like char[10]). This is the exemple from cmaster : char (*p)[10].

Well let's see:
This will likely lead to errors because p[1][0] (among others) points to invalid memory locations.
This is undefined behavior because you pass an uninitialized pointer to realloc().
That code possibly leaves uninitialized pointers all over the place.
This code loops from [1, 10), where I would expect [0, 10). So it's also terrible.
Therefore:
All of these are terrible. The correct code is either:
char (*p)[10] = malloc(10 * sizeof(*p));
Or:
char **p = malloc(10 * sizeof(*p));
for (int i=0; i<10; ++i)
p[i] = malloc(10 * sizeof(**p));

Related

Indexing the memory of a double pointer in C

In the piece of code below, what does the line: p[1]=p[0] entail? Does that mean that the data allocated to the p[0] is in the same address as p[1]? Also how is it even possible to utilize indexing when no memory has been allocated to each specific index of p? The code:
int i,j;
int **p = (int **)malloc(2 * sizeof(int *));
p[0] = (int *)malloc(2 * sizeof(int));
p[1] = p[0];
for(i = 0; i < 2; i++)
for(j = 0; j < 2; j++)
p[i][j] = i + j;
printf("%d",p[0][0]);
return 0;
I thank you in advance for sharing with me a part of your wisdom!
This looks like it's trying to create a 2D matrix that is 2x2 in size (as p[row][column]). However, only 1 row is actually allocated. Then p[1] = p[0]; means row 1 is pointing back to row 0. Essentially it's a 2x2 matrix where the both rows are identically the same.
This allocates two "pointers to a pointers" which allow you to use the row index p[row], but the rows still point to garbage at this point:
int **p = (int **)malloc(2 * sizeof(int *));
Then the actual row memory is allocated that allows you to use the column index p[row][column]:
p[0] = (int *)malloc(2 * sizeof(int));
The correct way to achieve an actual 2x2 matrix would be to allocate space for all 4 serialized values first like this:
p[0] = (int *)malloc(4 * sizeof(int));
Then have row 1 point to the 3rd element:
p[1]= &p[0][2];
This is not to say you should write your code this way (there are far better ways), it is just an explanation of the fishy code you provided.
Q1 and 2 :
p is defined as :
int **p = (int **)malloc(2 * sizeof(int *));
Then, p[0] and p[1] are int * so when you do p[1] = p[0], you are assigning to p[1] the same value than p[0] Careful, the pointers are assagned, not the value that they are pointing to, so if after this you change p[1][i], p[0][i] will also be changed
To better present this, I will try to draw the memory:
Before the assignment:
variable | Memory address
p[0]----points to----> 0xXXXX (x an arbitrary number)
p[1]----points to----> 0xYYYY (y an arbitrary number)
After the assignment:
p[0]----points to----> 0xXXXX
p[1]----points to----> 0xXXXX
Q3:
As p[1]=p[0] and you previously allocated p[0] , then p[1] points to the zone in memory that was alocated with :
p[0] = (int *)malloc(2 * sizeof(int));
Therefore there is not any issue. If you remove the p[1] = p[0] line, it should thow a segfault.
To create a 2x2 matrix, you should do:
int i;
int **p = malloc(2 * sizeof(int *));
for (i=0; i<2; i++)
p[i] = malloc(2 * sizeof(int));

Reallocating memory for a two dimensional array in C

My goal is to dynamically reallocate memory for a two dimensional int array in C. I know there are already several questions about that topic, but unfortunately my code does not run properly and i don't know what is going wrong.
First i am allocating memory:
int n = 10;
int m = 4;
int** twoDimArray;
twoDimArray = (int**)malloc(n * sizeof(int*));
for(int i = 0; i < n; i++) {
twoDimArray[i] = (int*)malloc(m * sizeof(int));
}
And initializing the array with integer numbers:
for(int i = 0; i < n; i++) {
for(j = 0; j < 4; j++) {
twoDimArray[i][j] = i * j;
}
}
Then i use realloc() to reallocate memory dynamically:
int plus = 10;
int newArraySize = n + plus;
twoDimArray = (int**)realloc(twoDimArray, newArraySize * sizeof(int));
I am expecting my aray twoDimArray to be accessible at [10][0] now, but when running
printf("twoDimArray[10][0] = %d\n", twoDimArray[10][0]);
i get an "EXC_BAD_ACCESS" runtime error.
Probably i am missing something rather simple, but since i am new to C and can't figure out my mistake. Any help is appreciated.
reallocating the array of pointers is necessary, but then you have only n values that point to something valid. You need to allocate the rest of the sub-arrays because the newly allocated memory points to unallocated/invalid areas. The error is not from accessing the pointer, but from dereferencing it.
You need to add something like:
for(int i = n; i < n+plus; i++) {
twoDimArray[i] = malloc(m * sizeof(int));
}
(same goes for deallocation: first deallocate the arrays in a loop, then deallocate the array of pointers)
Aside:
assigning the result of realloc directly to the original variable can be a problem if realloc returns NULL. Even if it's rare in those resizing cases (Under what circumstances can malloc return NULL?), you should copy the result in a temp variable, check for NULL, and free the old pointer if reallocation failed.
Do I cast the result of malloc?

Getting an invalid initialiser error

Why am I getting an "invalid initializer error" for the below code?
#include<stdio.h>
#include<malloc.h>
int main(){
int i = 2;
int j;
for(j = i ; j < 20; j++){
char *p[5] = malloc(20 * sizeof(char));
int len = 0;
p[0] = 'a';
}
return 0;
}
You have an Array of Pointers, and you're asigning only one Pointer to it:
char *p[5] = malloc(20 * sizeof(char));
Use this instead:
char *p = malloc(20 * sizeof(char));
If you actually want an Array of Pointers, but only set the first of them, this should be your code:
char *p[5] = {malloc(20 * sizeof(char))};
(Or, even better: char *p[5] = {0}; p[0] = malloc(20 * sizeof(char));)
If this is what you want, you have to asign the letter 'a' differently - use *(p[0]) = 'a'; instead.
Furthermore: you don't free your memory anymore. You should use free(p); to do this, otherwise it's possible that your program consumes more and more memory.
For small programs, this is no problem, because the OS frees the memory anyways after the Program has been closed.
But it's bad practice, and the reason for lots of bad software.

C - What happens to an array of pointers when the array is freed?

I am currently programming in C, and I am creating an array of pointers. These pointers contained in the array will last for the duration of the entire program.
Let's say the array of pointers is array A. I then create another array of pointers B, and I put an element of array A into array B. Then, I free array A.
What will happen to the element in array B? Will it no longer be valid since array A has been freed, or will it still be valid, since the actual pointer is still valid in memory?
Thanks
Here's an example of what my code will look like--
int a = 1;
int b = 2;
int c = 3;
int **array_a = (int **) malloc (sizeof (int *) * 3);
array_a[0] = &a;
array_a[1] = &b;
array_a[2] = &c;
int **array_b = (int **) malloc (sizeof (int *) * 1);
array_b[0] = array_a[0];
free(array_a);
Now, what happens to array_b[0]?
If you do this
int *a = malloc(10 * sizeof(int));
for (int i = 0 ; i != 10 ; i++) {
a[i] = 2*i+1;
}
int *b = a;
free(a);
then b would be invalid as well.
If you do this, however
int *a = malloc(10 * sizeof(int));
for (int i = 0 ; i != 10 ; i++) {
a[i] = 2*i+1;
}
int *b = malloc(10 * sizeof(int));
memcpy(b, a, 10 * sizeof(int));
free(a);
then b remains valid.
The pointers itself doesn't change, it still points where it pointed. The only thing is that the location it points to might be allocated to some other program. You could still write and read the location with undefined behaviour. Check this code:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *a = (int *)malloc(3 * sizeof(int));
a[0] = 1, a[1] = 2, a[2] = 3;
free(a);
// a = NULL // if you add this, the following will crash.
printf("%d\n", a[0]);
printf("%d\n", a[1]);
printf("%d\n", a[2]);
return 0;
}
If you are lucky, you could still get the correct result. But it's just luck.
So it's usually good idea to set the pointer to NULL after being freed.
So I just learned a little bit about free() not too long ago, so I'm sorry to say I don't know too much about it yet, but here's the little that I do know:
To return dynamically allocated memory to the system, you use the free() function. My professor used this kind of example:
struct listNode *Bob;
Bob = &any instance of listNode;
free(Bob);
So I believe B will still remain valid while A is no longer referenced. Java periodically collects dynamically allocated memory that is no longer referenced and it goes in the 'garbage.' C doesn't do that, which is why we use free(). Hope that helps a bit. I'm still learning myself. Good question :)
C interprets an array as the address of the base element, so depending on how you have freed the array you may not have freed the element at all.
However, assuming you did free all the elements of the array, your pointer in array B will still be there (it will still point to the same location in memory). However, you really don't know what is at that location because you already freed the memory there. You may still get the original data stored there, or it may have been overwritten. Definitely not safe to use it, though.
These three lines declare memory for three integers, and initialize the integers. Should you do this outside of a function, you can happily take the address of these variables and store them in your array.
int a = 1;
int b = 2;
int c = 3;
However, should the above three variables be declared in a function (on the stack) and you take the address of them, and store those addresses somewhere, you have created a (potential) dangling pointer problem.
This line allocates enough memory to hold three pointers to int (12 or 24 bytes),
int **array_a = (int **) malloc (sizeof (int *) * 3);
Now you store the address of the earlier defined variables a,b,c into the array_a[],
array_a[0] = &a;
array_a[1] = &b;
array_a[2] = &c;
Which is either perfectly harmless, or very dangerous, depending upon where a,b,c were declared, for example,
int** youfun()
{
int a = 1;
int b = 2;
int c = 3;
int **array_a = (int **) malloc (sizeof (int *) * 3);
array_a[0] = &a;
array_a[1] = &b;
array_a[2] = &c;
return(array_a); //very bad!
}
int a = 1;
int b = 2;
int c = 3;
int** mefun()
{
int **array_a = (int **) malloc (sizeof (int *) * 3);
array_a[0] = &a;
array_a[1] = &b;
array_a[2] = &c;
return(array_a); //safe, but strange
}
Declaring and allocating space for array_b[], and reserving a single memory location is similar to declaring and array of one pointer to int,
int **array_b = (int **) malloc (sizeof (int *) * 1);
The following assignment places the contents of array_a[0] (which is the address of variable a, &a, from above), and is only as dangerous/innocuous as having the &a stored in array_a[0],
array_b[0] = array_a[0];
Freeing the array_a is harmless, because nothing is stored in array_a which might 'leak', and does not affect array_b[0], as that contains the address of a, &a,
free(array_a);
Suppose you did the following instead,
int **array_a = (int **) malloc (sizeof (int *) * 100);
int ndx;
for(ndx=0; ndx<100; ++ndx)
array_a[ndx] = malloc( sizeof(int) );
You would now have allocated 100+1 memory locations, which is still fine.
Then suppose you allocated array_b will enough space to hold all of array_a[],
int **array_b = (int **) malloc (sizeof (int *) * 100);
int ndx;
for(ndx=0; ndx<100; ++ndx)
array_b[ndx] = malloc( sizeof(int) );
This would leak memory (pointed at by array_b), plus the memory pointed at by each array_b[ndx], for a total of 100+1 memory location leaks,
array_b = array_a; //discarded memory references at array_b[0..99], and array_b
Now suppose you did both of these,
array_b = array_a; //you just discarded the memory references at array_b[0..99] and array_b
free(array_a); //you just discarded array_a[0..99]
The above would leak all memory pointed to by array_b, array_b[0..99] and all memory at array_a[0..99], as you only copied array_a's address, not the addresses at array_a[0..99].
Here is how you would copy the memory allocated at array_a[0..99],
for(ndx=0; ndx<100; ++ndx)
array_b[ndx] = array_a[ndx];

Why am I getting segmentation fault for malloc() while using pointer to pointer?

I don't understand why this works:
void main() {
int * b;
b = (int *)malloc(sizeof(int));
*b = 1;
printf("*b = %d\n", *b);
}
while this does not (gets segmentation fault for the malloc()):
void main() {
int ** a;
int i;
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
}
since I find a[i] is just like b in the first example.
BTW, a[i] is equal to *(a+i), right?
You need to allocate memory for a first, so that you can access its members as a[i].
So if you want to allocate for 4 int * do
a = malloc(sizeof(int *) * 4);
for (i = 0; i<= 3; i++) {
...
}
or define it as array of integer pointers as
int *a[4];
a is a 2 dimensional pointer, you have to allocate both dimension.
b is a 1 dimensional pointer, you have to allocate only one dimension and that's what you're doing with
b = (int *)malloc(sizeof(int));
So in order the second example to work you have to allocate the space for the pointer of pointer
void main() {
int ** a;
int i;
a = (int**)malloc(4*sizeof(int*));
for (i = 0; i<= 3; i++) {
a[i] = (int*)malloc(sizeof(int));
*(a[i]) = i;
printf("*a[%d] = %d\n", i, *(a[i]));
}
The allocated pointer is written to uninitialized memory (you never set a to anything), causing undefined behavior.
So no, it's not at all equivalent to the code in the first example.
You would need something like:
int **a;
a = malloc(3 * sizeof *a);
first, to make sure a holds something valid, then you can use indexing and assign to a[0].
Further, this:
a[i] = (int*)malloc(sizeof(int));
doesn't make any sense. It's assigning to a[i], an object of type int *, but allocating space for sizeof (int).
Finally, don't cast the return value of malloc() in C.
actually malloc it's not that trivial if you really want safe and portable, on linux for example malloc could return a positive response for a given request even if the actual memory it's not even really reserved for your program or the memory it's not writable.
For what I know both of your examples can potentially return a seg-fault or simply crash.
#ruppells-vulture I would argue that malloc is really portable and "safe" for this reasons.

Resources