Program executable problem created in c

Asked

Viewed 257 times

1

Well, I am currently facing a somewhat strange problem here with my program in c. I am creating a program in c that le integers of an external text file (using the standard library and fscanf function) and storing in a dynamically allocated vector (I’m using the malloc and realloc functions). The program worked perfectly on two computers, both running directly from the IDE (using codeblocks with gcc) and on the generated . exe. The strange thing is that in the other two computers I tested, both work perfectly when I run in codeblocks, but in one when I run by . exe generated it does not read the file data and another gives error. What might be occurring? Thanks if someone can help.

The code is a bit big, so I’ll put some important functions.

Function allocating the data:

int leDados(DADOS *dado){
int i = 0;
unsigned long int tamanho = 0;
FILE *arq;
arq = fopen("dados/config.txt","r");
tamanho = sizeof(DADOS);
while(fscanf(arq, "%d", &dado[i].id) != EOF){
    tamanho += sizeof(DADOS);
    dado = realloc(dado, tamanho);
    i++;
}
fclose(arq);
return i;

}

  • The troublemakers are 64bits or vice versa?

  • All windows I tested are 64 bits.

  • The problem appears to be a problem of Behavior Indefinite: tatnto can function as the programmer expects otherwise. Anyway it takes more information to be able to answer.

  • What other information could be useful? Have you no idea what could be causing this instability? One question I have: O . exe generated externally is not the same used by the IDE to run the program?

  • 1

    "What other information could be useful?" -- The code! the loops, the input readings, the data structures, ...

  • I put there the function that allocates the vector dynamically. I believe the error is there, because it is at this point that the program fails.

Show 1 more comment

3 answers

0

Passing parameters by refection - with pointers, using * - is not magic! it is necessary to understand what she does - In C we indicate that a function receives a pointer, with "*", practically only to make the program easier to read - depending on the configurations the compiler can give a Warning or an error if we use it incorrectly - and depending on how wrong we use it, the compiler has nothing to do - nor can he warn 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 assume that its leDados is called with the vector dado at memory position "1000".

When you change something in the content of that pointer - you want to change any existing [i] value, it will work - and that’s how the reference call is used.

However, you try to make a change to the pointer address itself! When you write dado = realloc(dado, tamanho); the value 1000 data may remain the same, but only if the realloc achieve greater memory space in the same block - but it can return another value - if you cannot increase the space allocated at address 1000 to the requested size, the call can transfer your data to another address (for example, 2000) - and returns "2000" which is in the local variable dado. References within the same function to vector elements will continue to function - because they will be based on the new address "2000" - but the function that called leDados only knows the address 1000 - (and leDados there’s no changing that). When returning from the function leDados, hi 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 the realloc always be able to expand the memory block at the initial address (1000 in our example), who calls leDados continues with a valid reference to the vector. But if the realloc had on some call that move the data block, the program gets lost. And the factors for this call having to change the position are numerous - having to do with the internal functioning of the system, and specific settings for the process profile. Anyway, even when this program works the way 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 to 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 vector size:

#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 the memory address itself 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’re doing exercises to learn better C, and wanting to improve your understanding of pointers - that is - if you’re facing a real computing problem that you want to solve with this program on a personal computer it’s time to learn another language and not do this program in C. (Another use case for real C programs is if you are programming to run on a minicomputer, or microcontroller, such as Rduíno, or another 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 like Ruby, Python, PHP, Javascript, there are ready-to-use databanks, with all the part of Mea allocation, Elemtnos search, etc... ready to use.

For example, to read this same file in a Python program, putting all the numbers in a structure that the language would already prohibit memory, already knows the size, allows sorting, deletion, etc, you need to do:

dado = [int(n) for n in open(dados/config.txt").read().split()]

And then you just worry about using your numbers.

0

Following your same line of reasoning, follow a complete and tested solution to your problem:

#include <stdio.h>
#include <stdlib.h>


void exibir_numeros( int numeros[], int qtd )
{
    int i = 0;

    for( i = 0; i < qtd; i++ )
        printf("n[%d] = %d\n", i, numeros[i] );
}


int carregar_numeros( const char * arq, int * numeros[], int * qtd )
{
    FILE * pf = NULL;
    int n = 0;
    int i = 0;
    int * p = NULL;

    pf = fopen( arq, "r" );

    if(!pf)
        return -1;

    while( fscanf( pf, "%d", &n ) != EOF )
    {
        i++;
        p = realloc( p, i * sizeof(int) );
        p[ i - 1 ] = n;
    }

    fclose(pf);

    *qtd = i;
    *numeros = p;

    return 0;
}

/* fim-de-arquivo */

Compiling (Linux/GCC):

$ gcc -Wall numeros.c -o numeros

Input File:

1
2
3
100000
12345678
123456789
0987654321
1212121212
20000
30000
314215
6547438738
89234658725
-1000
-3000

Exit:

$ ./numeros teste.txt
n[0] = 1
n[1] = 2
n[2] = 3
n[3] = 100000
n[4] = 12345678
n[5] = 123456789
n[6] = 987654321
n[7] = 1212121212
n[8] = 20000
n[9] = 30000
n[10] = 314215
n[11] = -2042495854
n[12] = -959654491
n[13] = -1000
n[14] = -3000

I hope I’ve helped!

0

Only with what you put is difficult to say where is the error, but I can point out some possible problems. What I suggest is to use a thresher. This will allow you to understand exactly what the computer is doing.

Come on:

int leDados(DADOS *dado){
    // dado pode ser NULL? vc sempre passa algo que já está alocado?

    int i = 0;
    unsigned long int tamanho = 0;
    FILE *arq;
    arq = fopen("dados/config.txt","r");
    // tem certeza que deu certo a abertura do arquivo? arq é um ponteiro 
    // válido?

    tamanho = sizeof(DADOS);

    // dado tem uma alocação válida aqui? lembre-se não vale se estiver 
    //na pilha, tem que estar no heap
    while(fscanf(arq, "%d", &dado[i].id) != EOF){
       tamanho += sizeof(DADOS);
       dado = realloc(dado, tamanho);
       // a reallocação deu certo? Vc sempre vai jogar fora uma
       // realocação? Pq, quando der EOF, uma realocação vai estar perdida
       i++;
    }
    fclose(arq);
    return i;
}

As a final comment, remember that every time you enter the loop, you make a relocation, it makes your program look underrated. A relocation is an expensive operation. If each line in your file corresponds to an integer, it can be more interesting to count how many lines you have in your file, make a complete allocation and then fill it with values.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.