Ir ao conteúdo
  • Cadastre-se

C Ministério da Economia de Memória - ponteiros e alocação dinâmica


ReginaldoPaz
Ir à solução Resolvido por ReginaldoPaz,

Posts recomendados

Pessoal, estou com esse problema do curso pra resolver e estou muito perdido. Gostaria que se alguém pudesse esclarecer com código comentado pra eu entender principalmente sobre as funções que ele pede pra fazer com alocação dinâmica fico grato. (Já li algumas documentações e assisti alguns vídeos mas tá muito abstrato pra eu implementar na questão :( )

 

O presidente Chromonaro fez uma divisão igualitária da memória do computador para guardar um texto de várias linhas. Como o presidente não conhecia muito bem esse negócio de memória, resolveu chamar o Paulo Mozilla, Ministro da Economia de Memória, para dar uma olhada no planejamento e melhorar o que desse.

- Sr. Presidente, claro que não vai caber na memória, tem um monte de linha desse texto que é muito menor do que a quantidade que o senhor disponibilizou, vai gastar, o Sistema Operacional não vai gostar. Falou o ministro desconfiado...

- Tá OK! Vamo cortar isso aê. Disse o presidente em tom de ordem, depois de ouvir a sugestão do Ministro.

Para dizer que entendia do assunto o Ministro rapidamente fez um rascunho de como ficaria o código:

 

int main(){
  char str[10];
  int N;   
  scanf("%d\n", &N);
  char *linhas[N];
  
  for(int i=0; i<N; i++)
    linhas[i]=NULL;   
  
  do{
    fgets(str,10,stdin);
  }while(adicionarLinhas(N, linhas,str));

  printf("Texto liberado pelo Ministro\n");
  imprimirLinhas(N, linhas);
  
  liberarLinhas(N, linhas);
  return 0;
}

Mas na hora de implementar a função 'adicionarLinhas' o ministro entregou para você o trabalho. A função 'adicionarLinhas' deve receber a string como parâmetro que deve ser adicionada ao vetor 'linhas'. Veja que a string recebida pela função não corresponde a uma linha completa, assim antes de começar a preencher o próximo elemento no vetor linhas a função deve verificar se a ultima string adicionada tem um finalizador de linha '\n'.

Além disso, por ordem do Ministro da Economia de Memória, o seu programa deve armazenar cada linha de texto em uma string com o tamanho exato para caber a linha toda. A função deve retornar 1 enquanto o vetor ainda tiver espaço e 0 quando não houver mais espaços e a última linha foi lida.

Por fim você também precisa implementar as funções imprimeLinhas que imprime as linhas lidas e a função liberarLinhas que libera todas as linhas alocadas. Veja que, dependendo do valor de N, a entrada pode ser cortada, pois o Ministro resolveu cortar uma parte do texto que seria guardado a fim de economizar mais memória.

Link para o comentário
Compartilhar em outros sites

Vejo muitos casos parecidos em que se tem conhecimentos, porém falta sagacidade [depreender ou alcançar a resposta]; é muito comum, deparo-me  com isso "diariamente" é como uma porta que devesse [tentar] abrir sozinha e não correr o risco de ficar o "resto da vida" com ajuda nesse sentido. Em fim, a sua dúvida é, na verdade, um pedido de resolução e julgo que nesse caso vale mais apenas VOCÊ tentar [recomendo porque tenho formação com psicologia]. 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

4 horas atrás, ReginaldoPaz disse:

algumas documentações


E que "documentações seriam essas?
 

4 horas atrás, ReginaldoPaz disse:

assisti alguns vídeos mas tá muito abstrato

 

Poderia citar algum desses abstratos vídeos?

 

Poderia falar de suas maiores dúvidas?

 

4 horas atrás, ReginaldoPaz disse:

código comentado pra eu entender principalmente sobre as funções que ele pede pra fazer com alocação dinâmica fico grato. (Já li algumas documentações e assisti alguns vídeos mas tá muito abstrato pra eu implementar na questão :( )


Entendo. Codificado e comentado deve mesmo ajudar hein? ;) 

 

De volta ao programa 


O enunciado é b0b1nh0, o programa é ruim, incompleto, e ERRADO.

 

Mas o conceito é o mais importante e provavelmente o responsável pelo sucesso de C e C++ como linguagem de desenvolvimento de sistemas. E C em particular foi escrita para isso (e para programar um jogo também. Ken Thompson reconheceu isso várias vezes). Mas C foi escrita para ajudar a escrever o sistema Unix. Que "inspirou" o Linux,  que "inspirou" o MacOS e o Android. E o Windows. Muito inspirador :) afinal.

 

Todo programa em C ou C++ começa exatamente por isso que esse programa faz. O protótipo de main é
 

    int    main( int argc, char*[] argv);  

 

Em java não é muito diferente:
 

    public static void main ( String[] args ) {}

 

E suas funções podiam ser

 

char*       adicionarLinhas(int N, char* linha[], char* string){ return NULL; };
int         imprimirLinhas(int N, char* linha[]){ return 0; };
int         liberarLinhas(int N,char* linha[]){ return 0; };

 

Mas ainda não seria suficiente para dar certo.

 

Foi você que escreveu esse programa que postou? Espero que não tenha vindo de algum tipo de instrutor.

 

 

A diferença entre main() e esse programa

 

O fato é que o sistema operacional constrói essa lista de argumentos e passa para todo programa. São os parâmetros da linha de comando.

 

Num exemplo simples, se você digitar "coisa x.txt" na console do Windows o programa coisa.exe vai receber

  • argc = 2
  • argv[0] vai ser uma string com o caminho completo do programa no disco
  • argv[1] vai ser "notepad.txt"

Isso porque main() é declarada como eu disse
 

    int main(int argc, char* argv[]);

 

E argv é então um vetor de strings --- um ponteiro para char, char* denota o endereço de uma string em C. Os colchetes denotam um vetor. Então argv é char*[]. Pode ser descrito também como char** mas não vem ao caso aqui a distinção.

 

 

Então todo programa recebe algo assim pronto. Mas seu programa deve construir essa lista a partir das strings lidas via scanf(). 

 

Só que linhas[] em seu programa é um vetor de linhas e não um vetor de strings. Isso é o que o enunciado quer dizer.

 

Toda linha de texto é uma string, mas nem toda string é uma linha de texto.

 

A diferença? Uma linha é uma string que termina por '\n'. Só isso. Depois do '\n' estará um zero, como toda string.

 

"Clube do Hardware\n" é uma linha, "Clube do Hardware" é uma string.

 

Sobre o programa

 

int main(){
  char str[10];
  int N;   
  scanf("%d\n", &N);
  char *linhas[N];
  
  for(int i=0; i<N; i++)
    linhas[i]=NULL;   
  

 

Isso está ruim. Declare main como eu expliquei ou ao menos "int main(void)" se não vai usar os parâmetros.

 

str será usado para ler cada string. Se a string tiver um newline no final então será uma linha e você adiciona ao vetor. 

 

Mas se o cara digitar "1234567890" e ENTER a string lida vai ler apenas "1234567890" já que só pode ler 10 bytes de cada vez:

 

    fgets(str,10,stdin);

 

Então você guarda isso e continua lendo. Se depois vier "ABCDEF" e '\n' sua string poderá ser gravada:
 

    1234567890ABCDEF\n

 

Não precisa zerar os ponteiros porque vai alocar todos, mas é boa prática.

 

Você não precisaria ver vídeos ou ler documentos abstratos para testar isso. Se já escreveu algum programa em C poderia escrever esse que deve ter umas 5 linhas. E testar isso você mesmo @ReginaldoPaz 

 

Experimente sempre. É um caminho bom para aprender.

 

  int N;   
  scanf("%d\n", &N);

 

Isso é bobagem: se não testar o retorno de scanf() e ela não leu nada, o que acha que vai ter como valor de N?

E se está aprendendo se acostume a sempre mostrar na tela o valor que leu até estar seguro. É grátis. E economiza muita dor de cabeça. Se o cara bateu a mão no X na hora de digitar o valor de N scanf() vai retornar zero. Você não testou p0rr@ nenhuma e N pode estar valendo 45654646. Que adianta seguir com o programa?

 

  char *linhas[N];
  
  for(int i=0; i<N; i++)
    linhas[i]=NULL;   

 

E isso não faz sentido. Qual o tipo de linhas? linhas é char*[], um vetor  para ponteiros de char. Você não pode declarar a partir de uma variável N. Tem que ser um valor constante.

 

Citação

 

Até existe uma construção para declarar assim, mas não é padrão, não é portável, e não é importante. Não iria aprender nada com isso.

 

 

 

 


Esse não é um forum de português mas provavelmente deveria ter declarado
 

    char* linha[N];


porque cada elemento do vetor aponta para uma linha então o plural só faz sentido na declaração e não no uso, e o uso é o que importa.

 

linha[0] aponta para uma string, mas no seu programa tem que ser uma LINHA, terminar por '\n", o retorno de linha, o popular newline.

linha[1] é igualzinho. e linha[2] e tal. Até o fim das linhas.

 

Escreva algo mais, pergunte algo mais, poste código aqui e por certo a gente contunia te ajudando...

 

Como @mauro_b disse, e sua frase " Gostaria que se alguém pudesse esclarecer com código comentado pra eu entender" sugere, você parece buscar algo bem pronto.. :) 

 

Faça justiça oa tempo que gastamos respondendo e explicando para você e faça algo.

 

Um exemplo:

 

O programa abaixo, de 11 linhas e um comando só, o return, mostra um vetor de 3 strings e o programa rodando em um ambiente de teste, chamado debugger, que é um programa que roda o seu programa.

 

image.thumb.png.e6e689bf58fd3397af9e5fd100c708fc.png

 

E você vê que a segunda string tem um newline no fim. As outras duas não.

 

E você vê na janela sobre o programa os endereços de linha[0], [1] e [2], e o final

 

7b30, 7b34 e 7b38 nos endereços. Essa diferença, 4 bytes, é o tamanho de um ponteiro em Windows compilando em 32 bits. E fica claro que a partir de linha[0] tem uma sequência de ponteiros para char.

 

No seu exemplo isso deveria gerar uma ou duas linhas na saida:

"ABC\n" e talvez "DEF\n" se ao final você aceitar a string e colocar um '\n'

 

Pelo seu enunciado também não fica claro como o programa termina....

 

Sugiro testar a entrada e parar quando vier uma linha em branco. E testar a tal imprime_linhas() com com alguns valores afinal.

 

 

 

 

 

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

8 horas atrás, arfneto disse:


E que "documentações seriam essas?
 

 

Poderia citar algum desses abstratos vídeos?

 

Poderia falar de suas maiores dúvidas?

 


Entendo. Codificado e comentado deve mesmo ajudar hein? ;) 

 

De volta ao programa 


O enunciado é b0b1nh0, o programa é ruim, incompleto, e ERRADO.

 

Mas o conceito é o mais importante e provavelmente o responsável pelo sucesso de C e C++ como linguagem de desenvolvimento de sistemas. E C em particular foi escrita para isso (e para programar um jogo também. Ken Thompson reconheceu isso várias vezes). Mas C foi escrita para ajudar a escrever o sistema Unix. Que "inspirou" o Linux,  que "inspirou" o MacOS e o Android. E o Windows. Muito inspirador :) afinal.

 

Todo programa em C ou C++ começa exatamente por isso que esse programa faz. O protótipo de main é
 


    int    main( int argc, char*[] argv);  

 

Em java não é muito diferente:
 


    public static void main ( String[] args ) {}

 

E suas funções podiam ser

 


char*       adicionarLinhas(int N, char* linha[], char* string){ return NULL; };
int         imprimirLinhas(int N, char* linha[]){ return 0; };
int         liberarLinhas(int N,char* linha[]){ return 0; };

 

Mas ainda não seria suficiente para dar certo.

 

Foi você que escreveu esse programa que postou? Espero que não tenha vindo de algum tipo de instrutor.

 

 

A diferença entre main() e esse programa

 

O fato é que o sistema operacional constrói essa lista de argumentos e passa para todo programa. São os parâmetros da linha de comando.

 

Num exemplo simples, se você digitar "coisa x.txt" na console do Windows o programa coisa.exe vai receber

  • argc = 2
  • argv[0] vai ser uma string com o caminho completo do programa no disco
  • argv[1] vai ser "notepad.txt"

Isso porque main() é declarada como eu disse
 


    int main(int argc, char* argv[]);

 

E argv é então um vetor de strings --- um ponteiro para char, char* denota o endereço de uma string em C. Os colchetes denotam um vetor. Então argv é char*[]. Pode ser descrito também como char** mas não vem ao caso aqui a distinção.

 

 

Então todo programa recebe algo assim pronto. Mas seu programa deve construir essa lista a partir das strings lidas via scanf(). 

 

Só que linhas[] em seu programa é um vetor de linhas e não um vetor de strings. Isso é o que o enunciado quer dizer.

 

Toda linha de texto é uma string, mas nem toda string é uma linha de texto.

 

A diferença? Uma linha é uma string que termina por '\n'. Só isso. Depois do '\n' estará um zero, como toda string.

 

"Clube do Hardware\n" é uma linha, "Clube do Hardware" é uma string.

 

Sobre o programa

 


int main(){
  char str[10];
  int N;   
  scanf("%d\n", &N);
  char *linhas[N];
  
  for(int i=0; i<N; i++)
    linhas[i]=NULL;   
  

 

Isso está ruim. Declare main como eu expliquei ou ao menos "int main(void)" se não vai usar os parâmetros.

 

str será usado para ler cada string. Se a string tiver um newline no final então será uma linha e você adiciona ao vetor. 

 

Mas se o cara digitar "1234567890" e ENTER a string lida vai ler apenas "1234567890" já que só pode ler 10 bytes de cada vez:

 


    fgets(str,10,stdin);

 

Então você guarda isso e continua lendo. Se depois vier "ABCDEF" e '\n' sua string poderá ser gravada:
 


    1234567890ABCDEF\n

 

Não precisa zerar os ponteiros porque vai alocar todos, mas é boa prática.

 

Você não precisaria ver vídeos ou ler documentos abstratos para testar isso. Se já escreveu algum programa em C poderia escrever esse que deve ter umas 5 linhas. E testar isso você mesmo @ReginaldoPaz 

 

Experimente sempre. É um caminho bom para aprender.

 


  int N;   
  scanf("%d\n", &N);

 

Isso é bobagem: se não testar o retorno de scanf() e ela não leu nada, o que acha que vai ter como valor de N?

E se está aprendendo se acostume a sempre mostrar na tela o valor que leu até estar seguro. É grátis. E economiza muita dor de cabeça. Se o cara bateu a mão no X na hora de digitar o valor de N scanf() vai retornar zero. Você não testou p0rr@ nenhuma e N pode estar valendo 45654646. Que adianta seguir com o programa?

 


  char *linhas[N];
  
  for(int i=0; i<N; i++)
    linhas[i]=NULL;   

 

E isso não faz sentido. Qual o tipo de linhas? linhas é char*[], um vetor  para ponteiros de char. Você não pode declarar a partir de uma variável N. Tem que ser um valor constante.

 


Esse não é um forum de português mas provavelmente deveria ter declarado
 


    char* linha[N];


porque cada elemento do vetor aponta para uma linha então o plural só faz sentido na declaração e não no uso, e o uso é o que importa.

 

linha[0] aponta para uma string, mas no seu programa tem que ser uma LINHA, terminar por '\n", o retorno de linha, o popular newline.

linha[1] é igualzinho. e linha[2] e tal. Até o fim das linhas.

 

Escreva algo mais, pergunte algo mais, poste código aqui e por certo a gente contunia te ajudando...

 

Como @mauro_b disse, e sua frase " Gostaria que se alguém pudesse esclarecer com código comentado pra eu entender" sugere, você parece buscar algo bem pronto.. :) 

 

Faça justiça oa tempo que gastamos respondendo e explicando para você e faça algo.

 

Um exemplo:

 

O programa abaixo, de 11 linhas e um comando só, o return, mostra um vetor de 3 strings e o programa rodando em um ambiente de teste, chamado debugger, que é um programa que roda o seu programa.

 

image.thumb.png.e6e689bf58fd3397af9e5fd100c708fc.png

 

E você vê que a segunda string tem um newline no fim. As outras duas não.

 

E você vê na janela sobre o programa os endereços de linha[0], [1] e [2], e o final

 

7b30, 7b34 e 7b38 nos endereços. Essa diferença, 4 bytes, é o tamanho de um ponteiro em Windows compilando em 32 bits. E fica claro que a partir de linha[0] tem uma sequência de ponteiros para char.

 

No seu exemplo isso deveria gerar uma ou duas linhas na saida:

"ABC\n" e talvez "DEF\n" se ao final você aceitar a string e colocar um '\n'

 

Pelo seu enunciado também não fica claro como o programa termina....

 

Sugiro testar a entrada e parar quando vier uma linha em branco. E testar a tal imprime_linhas() com com alguns valores afinal.

 

 

 

 

 

Documentação no site "cplusplus", apostilas e vídeos da faculdade, vídeos no youtube, enfim, uma série de recursos pra tentar entender. Agradeço aos que responderam. Consegui resolver a questão.

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

33 minutos atrás, ReginaldoPaz disse:

Documentação no site "cplusplus", apostilas e vídeos da faculdade, vídeos no youtube, enfim, uma série de recursos pra tentar entender. Agradeço aos que responderam. Consegui resolver a questão

 

Poste o resultado para ajudar outros com a mesma dúvida. Esse é o propósito desses foruns: multiplicar

  • Curtir 1
Link para o comentário
Compartilhar em outros sites

  • Solução
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int adicionarLinhas(int N, char *linha[N], char *string){
    int tam = strlen(string);
    for(int i = 0; i < N; i++){
        if(linha[i] == NULL){
            linha[i] = (char*)malloc(tam*sizeof(char));
            strcpy(linha[i], string);
            return 1;
        }else if(linha[i][strlen(linha[i]) - 1] == '\n'){
            continue;
        }else{
            linha[i] = (char*)realloc(linha[i], strlen(linha[i])+10);
            strcat(linha[i], string);
            return 1;
        }
    }
    return 0;
}

void imprimirLinhas(int N, char *linha[N]){
    for(int i = 0; i < N; i++){
        printf("%s", linha[i]);
    }
}

void liberarLinhas(int N, char *linha[N]){
    for(int i = 0; i < N; i++){
        free(linha[i]);
    }
}

int main(){
    char str[10];
    int N;
    scanf("%d\n", &N);
    char *linhas[N];

    for(int i = 0; i < N; i++)
        linhas[i]=NULL;

    do{
        fgets(str, 10, stdin);
    }while(adicionarLinhas(N, linhas, str));

    printf("Texto liberado pelo Ministro\n");

    imprimirLinhas(N, linhas);

    liberarLinhas(N, linhas);

    return 0;
}

Demorei postar porque esqueci. rsrsrs

  • Obrigado 1
Link para o comentário
Compartilhar em outros sites

Crie uma conta ou entre para comentar

Você precisa ser um usuário para fazer um comentário

Criar uma conta

Crie uma nova conta em nossa comunidade. É fácil!

Crie uma nova conta

Entrar

Já tem uma conta? Faça o login.

Entrar agora

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

Ebook grátis: Aprenda a ler resistores e capacitores!

EBOOK GRÁTIS!

CLIQUE AQUI E BAIXE AGORA MESMO!