1. Este site usa cookies. Ao continuar a usar este site está a concordar com o nosso uso de cookies. Saber Mais.

C - malloc para uma estrutura

Discussão em 'Programação' iniciada por Genome_Boy, 3 de Maio de 2009. (Respostas: 14; Visualizações: 1787)

  1. Genome_Boy

    Genome_Boy Power Member

    Olá, tenho aqui uma duvida que talvez vocês me possam esclarecer.

    Criei uma estrutura do género:
    Código:
    typedef struct ex{
    struct ex* next;
    char* ch;
    }ex;
    typedef ex* ex_ptr;
    quando faço um malloc para a estrutura e depois para a string tenho feito:
    Código:
    ptr(def anteriormente) = (ex_ptr)malloc(sizeof(struct ex));
    ptr->ch=(char*)malloc(strlen(string usada));
    strcpy...
    Eu queria era saber se, sabendo previamente o tamanho da string, haverá maneira de fazer apenas um malloc que já incorpore o tamanho total.

    Cumps,
    genome_boy
     
  2. Mach4_PT

    Mach4_PT Power Member

    Código:
    ptr->ch=(char*)malloc(strlen(string usada));
    Isso esta a fazer um malloc de tamanho em bits igual ao numero de caracteres.
    devias ter feito ... malloc(strlen(string usada)*sizeof(char));
     
  3. Aparicio

    Aparicio /dev/mod
    Staff Member

    Queres com o malloc alocar espaço para a estrutura e a string?
    Isso não dá porque o ch é um ponteiro, tens que lhe alocar memória, que vai ficar fora da estrutura.

    Mas se declarasses a string por exemplo com char ch[32]; o tamanho da estrutura retornado pelo sizeof já incluí o tamanho da string, pelo que só fazes o malloc da estrutura.

    O malloc aloca bytes, não bits, se o tamanho do char for 1 byte que é o normal, até pode por só strlen(string usada), mas para garantir a compatibilidade em todas as máquinas é que convém por o *sizeof(char).
     
  4. Mach4_PT

    Mach4_PT Power Member

    Ooops :(
    My bad :P
     
  5. countzero

    countzero Power Member

    E já agora, não esquecer o terminador nulo para a string ('\0'). Logo (strlen(string) + 1) * sizeof(char). Senão, tens um off-by-one overflow.

    Cumps,
    JP
     
  6. Genome_Boy

    Genome_Boy Power Member

    Sim, eu tenho isso só que não escrevi aqui. :P
    Já agora deixo aqui uma outra dúvida, acerca de uns erros reportados pelo Valgrind.
    Tenho algo do género:
    Código:
    static strl_ptr first_str = NULL; /*variavel global*/
    char* str_cpy;[FONT=monospace]
    strncpy(str_copy, buffer, tam);
    ...
    if(first_str == NULL){
    first_str = (strl_ptr)malloc(sizeof(struct str_list));
    first_str->strg = (char*)malloc(1+strlen(str_copy));[/FONT]


    Ao correr o valgrind recebo o erro:
    Conditional jump or move depends on uninitialised value(s), na linha do if relacionada com strlen e na linha do 1º malloc relacionado com strcpy.

    Cumps
    genome_boy


     
  7. countzero

    countzero Power Member

    Tens que inicializar o str_cpy. Estás simplesmente a declarar str_cpy como ponteiro para char. Ou o declaras logo com espaço alocado na stack, p.e. char str_cpy[n], ou na heap com char *str_cpy = (char *) malloc(n);

    Cumps,
    JP
     
  8. Genome_Boy

    Genome_Boy Power Member

    E esse 'n' representa o quê? É que se de antemão não sei qual o tamanho que preciso (também uso essa var no strtok), não estou como alocar o espaço.

    Cumps, ;)
     
  9. countzero

    countzero Power Member

    Olhando para o teu código, sabes. Basta fazeres o strlen de buffer.

    Código:
    [FONT=Courier New][SIZE=2]static strl_ptr first_str = NULL; /*variavel global*/
    [/SIZE][/FONT] [FONT=Courier New][SIZE=2][COLOR=Yellow]char *str_cpy = (char *) malloc(strlen(buffer) + 1);[/COLOR][/SIZE][/FONT][FONT=Courier New][SIZE=2]
    strncpy(str_copy, buffer, tam);
    ...
    if(first_str == NULL){
    first_str = (strl_ptr)malloc(sizeof(struct str_list));
    [COLOR=Yellow]first_str->strg = str_cpy;[/COLOR][/SIZE][/FONT]
    
    No entanto, presumo que estejas a fazer uma lista ligada de strings e esse código é para alocares o nó inicial da lista.

    Há uma solução mais simples:

    Código:
    [FONT=Courier New][SIZE=2]static strl_ptr first_str = NULL; /*variavel global*/
    [/SIZE][/FONT] [FONT=Courier New][SIZE=2]
    ...
    if(first_str == NULL){
    first_str = (strl_ptr)malloc(sizeof(struct str_list));
    [COLOR=Yellow]first_str->strg = strdup(buffer);[/COLOR][/SIZE][/FONT] 
    
    Cumps,
    JP
     
  10. Genome_Boy

    Genome_Boy Power Member

    Sim, assim consigo resolver :)
    No entanto, lá mais para a frente não sei se será tão fácil:
    Código:
    char* var;
    var = strtok(str_cpy, " =");
    E em que depois faço o alocamento:
    Código:
       first_str = (strl_ptr)malloc(sizeof(struct str_list));
          first_str->strg = (char*)malloc(1+strlen(var));
          strcpy(first_str->strg,var);
    Neste caso ele também se queixa no strtok (aliás tb nos vários strtoks, que se encontram dentro de um while, sendo nesse caso var=strtok(NULL, " =")).

    Alguma sugestão (obrigado pelo ajuda até agora ;))

    Cumps
     
  11. countzero

    countzero Power Member

    Poderá ser um memory leak. Se estiveres a atribuir o ponteiro retornado pelo strtok sempre à mesma variável, estás constantemente a perder referências para a memória que o strtok tinha alocado previamente. Podes mostrar-me o código onde fazes o primeiro strtok e as chamadas seguintes já dentro do loop?

    Cumps,
    JP
     
  12. Genome_Boy

    Genome_Boy Power Member

    É algo deste género:

    Código:
    while(1){
    res =  fgets(buffer,MAX, stdin);
    if(res == NULL) break;
    
    str_copy = (char*)malloc(tam+1);
    strncpy(str_copy, buffer, tam);
    var = strtok (str_copy," ="); 
    
    while(var != NULL){
    vários testes para guardar a var na lista, todos do género:
          first_str = (strl_ptr)malloc(sizeof(struct str_list));
          first_str->strg = (char*)malloc(1+strlen(var));
          strcpy(first_str->strg,var);
    
    No fim
    var = strtok(NULL, " =");
    }
    free(str_copy);
    }
    O código basicamente lê linhas do stdin, e faz um while por cada linha, particionando-a e guardando os valores numa lista.

    Desculpa lá a falta de precisão, mas não o código aqui comigo e tive de escrever de cabeça.
     
  13. countzero

    countzero Power Member

    Olá.

    Tens aí, pelo menos, um memory leak. Tenta isto:

    Código:
    while(1){
         res =  fgets(buffer,MAX, stdin);
         if(res == NULL) break;
    
         [COLOR=Yellow]//str_copy = (char*)malloc(tam+1);
         //strncpy(str_copy, buffer, tam);
         
         var = strtok (str_copy," ="); [/COLOR]
         [COLOR=Yellow]while( var != NULL ) {[/COLOR]
             vários testes para guardar a var na lista, todos do género:
             first_str = (strl_ptr)malloc(sizeof(struct str_list));
    [COLOR=Yellow]         first_str->strg = var;
    [/COLOR][COLOR=Yellow]         var = strtok(NULL, " =");[/COLOR]
    [COLOR=Yellow]
             //first_str->strg = (char*)malloc(1+strlen(var));
             //strcpy(first_str->strg,var);  [/COLOR][COLOR=Yellow]
    
    
           //No fim
           //var = strtok(NULL, " =");[/COLOR]
         }
    [COLOR=Yellow]//free(str_copy);[/COLOR]
    }
    Cumps,
    JP
     
    Última edição: 6 de Maio de 2009
  14. Genome_Boy

    Genome_Boy Power Member

    Verifiquei que alteraste a parte do strtok. Ontem ainda não tinha feito nada, mas de qualquer maneira parecia-me que o strtok precisava aí de uns tweaks :P Vou experimentar agora e depois logo dou notícias.
     
  15. Genome_Boy

    Genome_Boy Power Member

    Bem o problema devia de estar mesmo relacionado com a variavel str_copy. Eu usava estava variável, para evitar um problema que surgia por vezes e que era o facto de algumas linhas terem no fim '\n' e outras não. Porém passei isso para o strtok, e deixei de usar a str_copy e agora não dá problemas nenhuns.

    Obrigado countzero!

    PS: Deixo aqui uma dúvida mais relacionada com UNIX. É possivel fazer abrir uma consola já numa determinada pasta? Se depois ter de estar a fazer 'cd' até ao directório pretendido?

    Cumps
     

Partilhar esta Página