Passing parameters by refining - with pointers, using * - is not magic!
you need to understand what it does -
In C we indicate that a function receives a pointer, with "*", practically just to make the program easier to read - depending on the configurations the compiler can give a warning or an error if we use this incorrectly - and depending on how wrong we use this, the compiler has nothing to do - nor can tell you. That's the case there.
So keep in mind that a pointer is a number. It indicates a position in the process memory. Let's suppose that your leDados
is called with the dado
vector at memory location "1000".
When you change something in the contents of this pointer - you want to change any existing given [i] value, this will work - and that's how the referral call is used.
However, you try to make a change in the pointer's own address!
When you type dado = realloc(dado, tamanho);
the value 1000
in data can remain the same, but only if realloc
gets more memory space in the same block - but it can return another value - if it can not increase the space allocated at address 1000 to the requested size, the call can transfer its data to another address (for example, 2000) - and returns "2000" that is in the local variable dado
. Referrals within the same function to vector elements will continue to work - why they will be based on the new address "2000" - but the function that called leDados
only knows the address 1000
- (and leDados
can not change that ). When returning from the read function, the program will try to read numbers in a position that is no longer allocated to the program data, and will give error.
The operation is intermittent, because if realloc
can always expand the memory block at the starting address (1000 in our example), the caller leDados
continues with a valid reference to the vector. But if realloc
had in some call that move the block of data, the program is lost. And the factors for this call having to change position are innumerable - having to do with the internal workings of the system, and specific settings for the process profile. Anyway, even when this program works as it is, it's just by chance.
The simplest way to solve, since this function fills the whole vector, is to allocate the initial vector in itself, and it returns the new pointer.
Use a default value, such as a sentinel value, for the rest of the program to know the size of the vector:
#define SENTINELA = 0x8fffffff
DADOS *leDados(){
DADOS *dado;
int i = 0;
while (...){ ...; i++}
dado[i] = SENTINELA
return dado;
}
Another way is to pass the address where the "given" address is - so that the "leDados" function can change its own memory address so that it is also changed in the calling function:
void main() {
DADOS * dado;
leDados (&dado);
}
...
int leDados( DADOS **dado){
...
while(fscanf(arq, "%d", &((*dado)[i].id)) != EOF){
*dado = realloc(*dado, tamanho);
...
}
...
return i;
}
And last but not least :
Unless you are doing exercises to learn better C, and wanting to improve your understanding of pointers - that is - if you are facing a real computing problem that you want to solve with this program on a personal computer it is time to learn another language and do not this program in C. (Another use case for real programs in C is if you are programming to run on a minicomputer, or microcontroller, such as arduino, or other IoT application)
In C you have to worry about everything: including allocating this data structure, and all the details of how you will manipulate it. In higher-level languages such as Ruby, Python, PHP, Javascript, there are data streams ready to use, with all the memory allocation, search of elements, etc. ... ready to use.
For example, to read this same file in a program in Python, putting all the numbers in a structure that the language already has memory, already knows the size, allows ordering, deletion, etc., you need to do:
dado = [int(n) for n in open(dados/config.txt").read().split()]
And then you just have to worry about using your numbers.