Storing values in a Dynamic array - c

I want to get numbers from the keyboard (or from a file: ./a.out < file) and store them in an array. The idea is that the length of the array is unknown.
#include <stdio.h>
#include <stdlib.h>
int* newElem(){
int* elm= malloc(sizeof(int));
if (elm == NULL) {
printf("\nError: memory allocation failed.\n");
exit(-1);
}
return elm;
}
int main(){
int *array,x,size,i=0;
while( scanf("%d",&x)==1 ){
array= newElem();
array[i]=x;
i++;
}
size=i;
free(array);
printf("size=%d",size);
return(0);
}
Why does this crash after I enter:
1 2 3 4 5 6 7 8

In your code
array= newElem();
is going to overwrite the existing pointer (memory) every time. so, array[i] becomes invalid, which essentially is an access out of bounds which in turn invokes undefined behavior. You need to use realloc() to re-size the allocated memory.

Simple.
array= newElem();
array[i]=x;
i++;
newElem() always return int[1] and you tried to access [n]

First you need to know that an array is a sequence of consecutive addresses.
This means that if the address of the first element is 0, the address of the second element will be 1, and the next 2, so on...
When you say x[10] in C, you are in fact saying *(x + 10), which means "from the first element (0), advance 10 addresses (+ 10), and give me the contents (* operator) of that address as an int.
So you see, there is a mathematical relation between elements, they are all next to each other in memory.
Now, to your code...
When you call array= newElem();, your pointer array points to the newly allocated address. However, any previous address array was pointing to before is lost, which is causing both your unexpected behavior and memory leak.
When you first call array= newElem(), lets suppose an integer is allocated at the address A, and the next time a new integer is allocated at the address B, and so on...
On first iteration, with i = 0:
while( scanf("%d",&x)==1 ){
array= newElem();
// array points to A
array[i]=x;
// array[0] = x
// or *(array + 0) = x
// same as *(array) = x
i++;
// i = 1
}
Now you will MOST LIKELY have an error (i = 1):
while( scanf("%d",&x)==1 ){
array= newElem();
// address A is lost, and now array points to B
array[i]=x;
// array[1] = x; -> likely an ERROR
// *(array + 1) = x
i++;
// i = 2
}
On the second iteration, you try to access the address NEXT TO the new address array points to, which would be C, that is why you get a violation.
Your code does not maintain a relationship between the elements of the array, you are essentially creating single integers in every iteration, and then trying
to access then but you are actually accessing invalid memory addresses.
It is not a very simple concept at first, comment if you need further clarification.

Related

Initialize an array in a loop (array vs malloc)

Hi I am quite new to C and I have a question about the behavior of array initialization using [] and malloc.
int main() {
int* pointer;
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
// expected 1 here, but got 99
printf("%d\n", pointer[1]);
return 0;
}
Why is the output 99? I thought the array is re-inited every loop, but it turns out using the same memory address. And if I use malloc to init the array instead, the result becomes 1 as expected.
Is there any way I could get result 1 without using malloc?
Your code is invalid as you access the variable which is out of the scope using the reference. It is undefined behaviour.
Every time you assign the i to the same element to the array. Pointer only references (points to) the first element of this array. So if you change the underlaying object the value you get using the reference will change as well. If your finger is pointing to the box of 5 apples and someone eats 2 apples, your finger will point to the box of 3 apples, not 5.
You need to make a copy of the object.
if(i == 1) {
pointer = malloc(sizeof(tmp));
memcpy(pointer, tmp, sizeof(tmp));
}
or break the loop (declaring it static or moving the tmp out of the for loop scope)
for(int i = 0; i < 100; i++) {
// Init the Array
static int tmp[2];
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
break;
}
}
The scope of the array tmp is the block scope of the for loop
for(int i = 0; i < 100; i++) {
// Init the Array
int tmp[2] = {};
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
// If the value is 1, copy that array pointer
if(i == 1) {
pointer = tmp;
}
}
That is in each iteration of the loop a new array tmp is created and ceases to be alive after exiting the block.
Thus the pointer pointer is invalid after the for loop. Dereferencing the pointer after the for loop invokes undefined behavior.
You have gotten the result 99 only because the array tmp was not being reallocated and the memory occupied by the array was not yet overwritten. So the last value stored in this extent of memory that is the value of i equal to 99 was outputted.
Even if you will declare the array tmp before the for loop then using the pointer pointer you will get as the output the value 99 that is the value last stored in the array.
You could write for example
int tmp[2] = { 0 };
int *pointer = tmp;
for(int i = 0; i < 100; i++) {
// Do some operation here...
tmp[0] = 0;
tmp[1] = i;
}
And the last value stored in the array (when i is equal to 99)
tmp[1] = i;
will be outputted in this call
printf("%d\n", pointer[1]);
Pay attention to that such an initialization with empty braces is invalid in C opposite to C++
int tmp[2] = {};
You need to write at least like
int tmp[2] = { 0 };
As we know pointer stores a memory address.
Here, I think when you give the command: pointer = tmp;,
the address of the array stored in 'tmp' is copied to the 'pointer'.
But when the loop of i = 1 gets completed, the array that you created in that particular loop and the pointer 'tmp' gets forgotten.
Then the loop for i=2 starts, 'tmp' and the array gets created again.
It happens again till the loop end.
I think that the program is storing tmp[1] at the same location every time due to which the data stored at that changes again and again.
So, when you give the command printf("%d\n", pointer[1]);, the data at that address get printed which is no longer equal to 1, it has changed.
The mistake is that we shared the address of 'tmp' with the 'pointer'.
But when we use malloc, we lock that memory means other programs can't use that memory. ( That's why we always need to free that memory to avoid memory leaks ).
It's the reason while using malloc you get output as 1 as your other commands can't touch that particular memory.
Solution:
If you want to solve the problem without malloc.
Initialise 'pointer' as an array to store data of 'tmp'.
use this code,
pointer[0] = tmp[0]; pointer[1] = tmp[1];
at place of
pointer = tmp;.
Now, you will not be copying addresses to 'pointer' but the data in the 'tmp'.
And if you have a big array with many values in it, just use it for loop.
solution image
Also, you will get the same problem if you do it like this, all because of copying only the address, you will be doing the same thing.
Maybe you can relate,same problem image
Thanks.

Go to item in array

I am looking at an example of calloc, and it says it creates pointer pointing to first element. So I was thinking, how could I pull an item out such as, if I had an array, car[5] = 1,2,3,4,5, I would then go to car[1] to pull a specific element out.
I can't do *parr[2] so I am thinking (*parr+2) would work however I'm not sure if its the correct way to do this.
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#define NUMBER_OF_ELEMENTS 100
int main(){
int32_t *parr = calloc(NUMBER_OF_ELEMENTS, sizeof(int32_t));
if (parr == NULL)
{
printf("Couldn't allocate memory");
}
else
{
printf("Memory allocation succesful");
printf("Item at start is,%d",(*parr+2));
}
}
You have allocated a simple one-dimensional array parr, use the array notation parr[2] to read or set the value at element 2. It's the same simple rules as array literal (same as car[5] in the question)
*(parr + 2) is also valid.
(*parr + 2) is (parr[0] + 2), it evaluates to 0 + 2 = 2
(*parr + 2) = 3; is invalid, because it can't assign 3 to 2.
*parr[2] is invalid, it can't be de-referenced.
It gets more complicated if the address of the array is passed to a function, or for multi-dimensional arrays.

Output void pointer from void double pointer array

I need to implement a variable length data array containing void pointers. And I ran into the problem that when trying to print from this array I always output the last element.
Here is an abstract illustration of my problem and attempted implementation:
#include <stdio.h>
#include <stdlib.h>
int main() {
int capacity = 4; // for example
void **array = malloc(capacity*sizeof(void*));
// assign values to array elements
for(int i = 0; i < capacity; i++) {
array[i] = malloc(sizeof(void*)); // not sure if it necessary
int a = i*i;
array[i] = &a;
printf("index: %d, element: %d\n", i, *(int*)array[i]); // for demonstration
}
printf("\n");
/*
* after that I try to print all the elements of the array sequentially
*/
for(int i = 0; i < capacity; i++) {
printf("index: %d, element: %d\n", i, *(int*)array[i]));
}
// I know that I do not free my memory, but that’s not the point
return 0;
}
Output that i get looks like:
index: 0, element: 0
index: 1, element: 1
index: 2, element: 4
index: 3, element: 9
index: 0, element: 9
index: 1, element: 9
index: 2, element: 9
index: 3, element: 9
(Edit the questions: in the comments they pointed out to me that the error was in the way of putting the variable in the mass, because I did not take into account the lifetime of the variable in the for-loop and the principle of the pointer)
How can I correctly fill a similar array without introducing a bunch of extra variables? Or the method that I chose is completely incorrect?
I would be grateful for any help
You see the "last element", because a stays at the same position of the stack in each iteration, and thus &a stores that particular single address into all elements. Then the address contains the last value written there - until it becomes complete garbage when anything else overwrites it.
You would need different addresses, so you would need to allocate memory for each number, inside the loop. Which kind of happens already, just you allocate memory for a void*, while you would need an int, and you overwrite it, which (as the comments point out already) you simply should not do:
array[i] = malloc(sizeof(int));
*(int*)array[i] = i*i;
printf("index: %d, element: %d\n", i, *(int*)array[i]); // for demonstration
Then it works: https://ideone.com/dF4KY8 (an extra ) has been removed from the end)
Of course, you would need to free() stuff, as your own comment suggests.
I hope, I can help you.
malloc reserves space (as you probably already know) and returns a void*, not a void**. I would initialize it with:
const int capacity = 4;
int* array = (int*)malloc(capacity*sizeof(int));
I wouldn't initialize the array as void** because you plan to store many ints in
it and an int array is nothing else than an int*.
If you already initialize the array in the beginning you have not to
call malloc again. 'malloc', returns the address, where the memory is allocated
for you but you already know, where you want to store the data. If you have a
void**, it is a multidimensional array. One thing left: On failure malloc returns a null-pointer a check whether the array is null, wouldn't harm you. :)
There is a ')' too much within the printf();

Assigning the value of a pointer at a certain index in C

I'm trying to understand this code:
struct mys {
double d[128];
};
void my_func(int iters) {
int i;
struct mys *ptr = malloc(iters *sizeof(struct mys));
for(i = 0; i < iters; i++) {
ptr[i].d[0] = (double)i;
}
free(ptr);
}
What I know:
mys is of size 8 * 128 (size of double is 8, it's an array of 128 doubles)
*ptr is of size iters * (8 * 128)
What is going on here:
ptr[i].d[0] = (double)i;
?
What I know:
// ptr->d is the address of the first part of d
// same as (*ptr).d
// BECAUSE d IS A STRUCT
// ptr->d[i] is the actual value. so, 0.0000
// same as (*ptr).d[i]
Thanks in advance.
ptr[i] is the value at index i, so starts at 0.0000.
d is not initialized, it is just the name of the member of a struct. How can we just d here?
What I think:
*ptr is multiple (iters) structs.
So, ptr[0] is the first struct, ptr[1] is the second struct, etc.
ptr[i].d access the ith struct's d array.
ptr[i].d[0] accesses the first index of the d array. So the line above sets that number to double(i).
So this really only sets the first element of each struct to be 0. Am I right?
But when iters is 2, and I try:
for(int i = 0; i < iters; i++) {
printf("%p\n", ptr[200].d);
}
it still prints an address. Why is that?
What is going on here: ptr[i].d[0] = (double)i;?
This:
struct mys *ptr = malloc(iters *sizeof(struct mys));
allocates memory for an array of structs, called ptr.
This line of code:
ptr[i].d[0] = (double)i;
assigns i to the first cell of the array d, of the i-th struct, in the array ptr.
i is casted to double, because d is an array of doubles, and i is declared as int.
when iters is 2, and I try: for(int i = 0; i < iters; i++) { printf("%p\n", ptr[200].d); } it still prints an address. Why is that? Shouldn't it be out of range since ptr is only 2 structs?
This is definitely out of range, since arrays are 0-indexed.
However, that attempt invokes Undefined Behavior (UB), which means that you don't know how the code is going to behave. For example, in your computer it prints an address, in my computer it might cause a segmentation fault, and so on...
So this really only sets the first element of each struct to be 0. Am I right?
It copies the index i, converted to type double, into the first element of each struct. Otherwise you are right.
Regarding the expression ptr[200].d, this is the same as &(ptr[200]) because the array d[] is the sole element of a mys object. Because a double is eight bytes wide, each mys object occupies (8 bytes)(128) = 1 kiB. Therefore, &(ptr[200]) == ptr + 200*1024. The last is an address 200 kiB past the beginning of *ptr. Whether the address has meaning depends on whether anything meaningful is stored there.

How can an empty array be involved in a calculation?

#include <stdio.h>
int f( int *x ) {
*x = 35;
}
int main( int argc, char *argv[] ) {
int p[32];
int *q = p + 5;
f( q );
printf( "%d", p[5] );
return 0;
}
Can you please explain why the output is 35?
I tried to output the value of p by using printf("%d", p) and right after int p[32], it returned a -2077686688.
I think it just simply because I didn't assign any value to the p[32] array yet, so it just returned a random number.
However, the part that confuses me the most is *q = p + 5
How can an array do that?
Since there is no value in the p array, how can it just return its size in this expression?
In your code, int p[32] sets aside an array of size 32 that can be referenced using p. When you define q to be p + 5, you are assigning q to be a pointer to the 6th (1-indexed) element in memory starting from wherever p points to.
When you pass q to f(), the value at q is set to 35 from whatever was there before (uninitialized memory). Since q points to the same location as p[5], p[5] will be 35 since that is the value set at the location in memory by f().
C is a low-level programming language and the behavior around using memory through C variables might be a bit confusing to programmers coming from languages with higher level abstractions.
Let's break down your main function first.
int p[32];
When a function is called in your program, it gets allocated some section in RAM assigned to your process. This section is called the stack. With this statement, you're telling the compiler that your function (main) needs space for 32 integers in stack. Further statements you make with the variable p will be operating on this space reserved for the 32 integers.
Note that, you're not telling anything to the compiler on how this portion of memory assigned for p is initialized. So all these bytes allocated for 32 integers will store whatever they contained before your function is called.
Let's look at the next one.
int *q = p + 5;
This is very similar but now you are asking for some memory in stack with a size that can fit "a pointer to a integer". Pointer is the C abstraction for bare "memory address with a type". So this space will be used to store addresses in memory, and these addresses will refer to another space in RAM that is intended to store integers.
You are also telling the compiler to initialize the stack space for q, with the value of p + 5. Unlike the space for the 32 integers above (p), the space for q will be initialized right after your function is called.
The expression p + 5 is applying what is called "pointer arithmetic". This is used to take an address in RAM, and go up or down based on whatever offset we need. Remember, p was an array and arrays in C work like pointers (addresses) when they take part in pointer arithmetic. Thus, what p + 5 really means is the "address that is 5 integers after the first address p points to". This ends up being the "pointer to the sixth element of p" (first being p[0]), in other words, the address of p[5].
f(q);
In this statement, you are passing the address stored in q, which happened to be the address of the sixth element in p. The function f in return assigns 35 to the location in RAM pointed by this address, hence changing the integer that would be accessed by p[5] to the integer value of 35.
Right at this point, p[5] is the only element within p that has an initialized value. All other integers in p will continue to store what they held before main was called during the initialization of your program.
printf( "%d", p[5] );
When the execution returns back to main, the integer that can be accessed by p[5] is now set to 35, and that is exactly what you expect to see with this printf statement.
int main() {
int p[32] = { 0 };
// initializing array with zeros; no mode random values in array!
int *q = p + 5;
if (&p == &p[0] && &3[p] == &p[3]) {
printf("Sick sad C world\n");
}
/* We can say that there's no such thing as 'array' in C!
* (actually, C has arrays)
* but C arrays are 'thin layer'; try to compare JS Array and C Arrays
* See this: https://stackoverflow.com/a/381549/10972945
* So: p[0] == *(p + 0) == *p
* 'Array' is an address of it's zero element! */
printf(
"p located at %p\n"
"p + 1 located at %p\n"
"p + 5 located at %p\n"
"Size of int (in bytes) is %zu\n",
(void*) p,
(void*) (p + 1),
(void*) (p + 5),
sizeof(int)
);
/* Try to run this code and substract addresses, one from another.
p located at 0x7ffee3e04750
p + 1 located at 0x7ffee3e04754
p + 5 located at 0x7ffee3e04764
Size of int (in bytes) is 4
See:
address of (p + 1) - address of p
== 0x7ffee3e04754 - 0x7ffee3e04750
== 4 == sizeof(int)
address(p + 5) - address(p)
== 0x7ffee3e04764 - 0x7ffee3e04750
== 0x14 == 20 == 5 * sizeof(int)
*/
}

Resources