alocação dinamica de memoria [RESOLVIDO]

1. alocação dinamica de memoria [RESOLVIDO]

Aterson lino
Atr

(usa openSUSE)

Enviado em 30/08/2019 - 21:53h

boa noite, estou lendo sobre alocação dinamica de memoria, porem me veio uma duvida!
tenho o seguinte codigo:

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

int main(void){
char *n;
n = (char *) malloc(100 * sizeof(n));
printf("Nome: ");
scanf("%c", &n);
printf("seu nome é %c\n", n);
n = NULL;

return 0;
}


e caso eu queira usar vetor, eu teria que usar um loop, minha duvida é a seguinte...
tem como capturar uma palavra digitada pelo usuario sem usar loops?
pois eu teria que saber quantos caracteres o user digitou, e não vejo muita eficiencia nisso, pois teria que digitar letra por letra!


  


2. MELHOR RESPOSTA

Perfil removido
removido

(usa Nenhuma)

Enviado em 30/08/2019 - 22:50h

use a função getline(3) para ler uma linha por vez:

char *line;
size_t len;
ssize_t r;

line = NULL;
len = 0;

/* a função getline já alloca o espaço necessario se o ponteiro recebido for nulo*/
r = getline(&line, &len, stdin); /* cheque por erros em codigo real */
printf("recebi: %s de tamanho %zd", line, r);

Lembre-se também syscalls são caros, evitar faze-los em excesso é bom para se ter um codigo eficiente, por exemplo quando você atingir
o limite de espaço de um "vetor" duplique-o ao invez de allocar só o espaço necessario (isso é caso espere continuar usando-o).
E caso já saiba de ante-mão o espaço que precisa, considere usar o stack ao invez do heap (de excessão espaços muito grandes).

3. Re: alocação dinamica de memoria [RESOLVIDO]

Aterson lino
Atr

(usa openSUSE)

Enviado em 01/09/2019 - 09:03h

eadwardus escreveu:

use a função getline(3) para ler uma linha por vez:

char *line;
size_t len;
ssize_t r;

line = NULL;
len = 0;

/* a função getline já alloca o espaço necessario se o ponteiro recebido for nulo*/
r = getline(&line, &len, stdin); /* cheque por erros em codigo real */
printf("recebi: %s de tamanho %zd", line, r);

Lembre-se também syscalls são caros, evitar faze-los em excesso é bom para se ter um codigo eficiente, por exemplo quando você atingir
o limite de espaço de um "vetor" duplique-o ao invez de allocar só o espaço necessario (isso é caso espere continuar usando-o).
E caso já saiba de ante-mão o espaço que precisa, considere usar o stack ao invez do heap (de excessão espaços muito grandes).

Poderia me explicar melhor sobre size_t e ssize_t?
Pelo que pesquisei, size_t é um tipo de unsigned int, e ssize_t retorna erro, estou certo?



4. Re: alocação dinamica de memoria [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 01/09/2019 - 09:32h

Atr escreveu:
Poderia me explicar melhor sobre size_t e ssize_t?
Pelo que pesquisei, size_t é um tipo de unsigned int, e ssize_t retorna erro, estou certo?

size_t é um tipo (unsigned) usado para representar o tamanho de qualquer objeto na memoria. ssize_t é a versão signed do mesmo, geralmente utilizado quando há a intenção de indicar erros por retornar um valor negativo.




5. Re: alocação dinamica de memoria [RESOLVIDO]

Aterson lino
Atr

(usa openSUSE)

Enviado em 01/09/2019 - 19:35h

eadwardus escreveu:

Atr escreveu:
Poderia me explicar melhor sobre size_t e ssize_t?
Pelo que pesquisei, size_t é um tipo de unsigned int, e ssize_t retorna erro, estou certo?

size_t é um tipo (unsigned) usado para representar o tamanho de qualquer objeto na memoria. ssize_t é a versão signed do mesmo, geralmente utilizado quando há a intenção de indicar erros por retornar um valor negativo.



Obrigado pela explicação!


6. Re: alocação dinamica de memoria [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 02/09/2019 - 05:28h

Atr escreveu:

boa noite, estou lendo sobre alocação dinamica de memoria, porem me veio uma duvida!
tenho o seguinte codigo:
#include <stdio.h>
#include <stdlib.h>

int main(void){
char *n;
n = (char *) malloc(100 * sizeof(n));


A linha acima está errada.

A conversão explícita para char * é redundante, porque a função malloc() já retorna um valor do tipo void *, que, em C, é automaticamente conversível e convertido para qualquer outro tipo de ponteiro. Ao colocar uma conversão explícita, você aumenta a quantidade de código em que tem de dar manutenção e não ganha absolutamente nada.

Mas o que está errado mesmo é o valor passado como argumento para a função. Ali, você pede para alocar espaço não para 100 caracteres, mas para 100 ponteiros para caracteres, pois o tipo de n é char *, não char.

Eis a forma mais correta de fazer.
n=malloc(100*sizeof n[0]);  // Vale para ponteiros de qualquer tipo (exceto “void *”). 


	printf("Nome: ");
scanf("%c", &n);


Mais dois (ou três, ou mesmo quatro) erros aqui.

O primeiro é que n já é um ponteiro, então você não deve usar o operador & para obter seu endereço. Se o fizer, a função scanf() vai sobrescrever o valor do ponteiro atribuído a n no momento da alocação, não o conteúdo da área alocada.

Outro erro é que a conversão "%c" é para ler apenas um caráter, não uma sequência de caracteres.

Ainda mais um problema é que você não está testando o valor retornado pela função para saber se a operação de leitura foi bem sucedida ou não.

Por fim, se você vai ler uma string que tem um tamanho máximo, deveria limitar a quantidade de caracteres recebidos, a fim de se proteger contra corrupção de memória caso a quantidade de dados lidos seja maior do que o espaço destinado a recebê-los.

	printf("seu nome é %c\n", n);
n = NULL;


Atribuir um valor nulo ao ponteiro não é suficiente para desalocar a memória que fora alocada. Você tem de usar a função free() para isso.



return 0;
}


e caso eu queira usar vetor, eu teria que usar um loop, minha duvida é a seguinte...
tem como capturar uma palavra digitada pelo usuario sem usar loops?


Se você vai ler uma cadeia de caracteres, então vai haver loops. Você pode até não enxergá-los, se substituir a leitura da cadeia explícita por uma chamada a uma função, mas dentro dessa função vai haver laços de repetição, com certeza.

pois eu teria que saber quantos caracteres o user digitou, e não vejo muita eficiencia nisso, pois teria que digitar letra por letra!


Você não precisa necessariamente fazer letra por letra, mas em blocos. Procure nos arquivos do fórum por “my_fgets”.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


7. Re: alocação dinamica de memoria [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 02/09/2019 - 09:41h

paulo1205 escreveu:
Eis a forma mais correta de fazer.
n=malloc(100*sizeof n[0]);  // Vale para ponteiros de qualquer tipo (exceto “void *”). 


Só um mini acrescimo, é possivel que ocorra overflow ao passar o numero de objetos em bytes (ao menos dessa forma), então se o valor que for alocado for determinado em "runtime" então é bom adicionar uma checagem.

size_t x;
[ ... ]
x = /* numero de objetos */
y = /* tamanho do objeto */
if (x && x > (size_t)-1/(y))
/* overflow */
malloc(x, y);



8. Re: alocação dinamica de memoria [RESOLVIDO]

Aterson lino
Atr

(usa openSUSE)

Enviado em 02/09/2019 - 13:21h

paulo1205 escreveu:

Atr escreveu:

boa noite, estou lendo sobre alocação dinamica de memoria, porem me veio uma duvida!
tenho o seguinte codigo:
#include <stdio.h>
#include <stdlib.h>

int main(void){
char *n;
n = (char *) malloc(100 * sizeof(n));


A linha acima está errada.

A conversão explícita para char * é redundante, porque a função malloc() já retorna um valor do tipo void *, que, em C, é automaticamente conversível e convertido para qualquer outro tipo de ponteiro. Ao colocar uma conversão explícita, você aumenta a quantidade de código em que tem de dar manutenção e não ganha absolutamente nada.

Mas o que está errado mesmo é o valor passado como argumento para a função. Ali, você pede para alocar espaço não para 100 caracteres, mas para 100 ponteiros para caracteres, pois o tipo de n é char *, não char.

Eis a forma mais correta de fazer.
n=malloc(100*sizeof n[0]);  ;; Vale para ponteiros de qualquer tipo (exceto “void *”). 


	printf("Nome: ");
scanf("%c", &n);


Mais dois (ou três, ou mesmo quatro) erros aqui.

O primeiro é que n já é um ponteiro, então você não deve usar o operador & para obter seu endereço. Se o fizer, a função scanf() vai sobrescrever o valor do ponteiro atribuído a n no momento da alocação, não o conteúdo da área alocada.

Outro erro é que a conversão "%c" é para ler apenas um caráter, não uma sequência de caracteres.

Ainda mais um problema é que você não está testando o valor retornado pela função para saber se a operação de leitura foi bem sucedida ou não.

Por fim, se você vai ler uma string que tem um tamanho máximo, deveria limitar a quantidade de caracteres recebidos, a fim de se proteger contra corrupção de memória caso a quantidade de dados lidos seja maior do que o espaço destinado a recebê-los.

	printf("seu nome é %c\n", n);
n = NULL;


Atribuir um valor nulo ao ponteiro não é suficiente para desalocar a memória que fora alocada. Você tem de usar a função free() para isso.



return 0;
}


e caso eu queira usar vetor, eu teria que usar um loop, minha duvida é a seguinte...
tem como capturar uma palavra digitada pelo usuario sem usar loops?


Se você vai ler uma cadeia de caracteres, então vai haver loops. Você pode até não enxergá-los, se substituir a leitura da cadeia explícita por uma chamada a uma função, mas dentro dessa função vai haver laços de repetição, com certeza.

pois eu teria que saber quantos caracteres o user digitou, e não vejo muita eficiencia nisso, pois teria que digitar letra por letra!


Você não precisa necessariamente fazer letra por letra, mas em blocos. Procure nos arquivos do fórum por “my_fgets”.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


eu escrevi esse código no celular pelo cppdroid e eu tive de fazer a conversão na mão se não dava erro e não compilava
por isso o (char *)
e sobre o %c no scanf() e printf(), eu escrevi originalmente como exemplo para pegar um caractere, a duvida de pegar uma palavra veio depois
e sobre o free(), eu li que era má ideia usar ele, sendo melhor usar NULL


9. Re: alocação dinamica de memoria [RESOLVIDO]

Perfil removido
removido

(usa Nenhuma)

Enviado em 02/09/2019 - 13:34h

Atr escreveu:
sobre o free(), eu li que era má ideia usar ele, sendo melhor usar NULL

Se você fizer isso você vazara memoria, ou seja perdera todas as referências para a memoria alocada, isso é extremamente indesejavel em runtime, você até pode omitir um "free()" se estiver proximo de fechar o programa (por exemplo se for abortar o programa devido a um erro), mas se tiver a intenção de mante-lo rodando você deve usar o free() e só então anular o ponteiro.



10. Re: alocação dinamica de memoria [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 02/09/2019 - 23:25h

eadwardus escreveu:

Só um mini acrescimo, é possivel que ocorra overflow ao passar o numero de objetos em bytes (ao menos dessa forma), então se o valor que for alocado for determinado em "runtime" então é bom adicionar uma checagem.


O valor daquela multiplicação não é determinado em tempo de execução, mas é uma multiplicação de constantes, resolvida pelo compilador em tempo de compilação. Caberia ao compilador detectar um possível overflow e emitir o alerta durante a compilação.

Além disso, numa máquina moderna de 64 bits, o produto em questão teria de ser superior a 18 quintilhões de bytes para dar overflow. Mesmo numa máquina de 32 bits, dificilmente alguém precisaria alocar um único array com mais do que 4GiB (no caso dos nossos PCs mais velhinhos de 32 bits, nem mesmo sei se isso é possível com um único array).

De todo modo, você tem razão no caso geral de multiplicações de fatores não-constantes, que ocorrem apenas em tempo de execução. Em princípio, toda multiplicação de fatores desconhecidos a priori está sujeita a overflow. Mas isso não significa que toda multiplicação tem de ser precedida de uma divisão, que é uma operação computacionalmente muito custosa, para assegurar que a multiplicação possa ser feita.

Creio que, em geral, o analista terá noção das faixas de valores dos fatores, e deve ter levado isso em consideração na hora de escolher os tipos de dados dos fatores e do produto, a fim de não precisar de fazer verificações. E para os casos em que de todo seja impossível prever os valores dos fatores, há, dependendo do contexto, meios mais baratos de verificar o risco de overflow, sem requerer necessariamente uma divisão.


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


11. Re: alocação dinamica de memoria [RESOLVIDO]

Paulo
paulo1205

(usa Ubuntu)

Enviado em 02/09/2019 - 23:49h

Atr escreveu:

eu escrevi esse código no celular pelo cppdroid e eu tive de fazer a conversão na mão se não dava erro e não compilava
por isso o (char *)


Note que eu fui explícito em dizer que a conversão explícita era desnecessária em C.

Não conheço o CppDroid, mas será que você não tem como mudar o modo dos programas que você edita nele de C++ para C? Se você compilar o programa como C, não vai receber nenhuma reclamação. Já se o compilar como C++, vai, porque a regra do C que diz que void * é automaticamente conversível para qualquer outro tipo de ponteiro simplesmente não vale em C++.

Se, por outro lado, você preferir continuar com C++, então deveria considerar evitar o uso de funções como malloc()/calloc()/realloc()/free(), preferindo mecanismos nativos do C++, como os operadores new/new[] e delete/delete[] ou classes que implementam containers, tais como std::vector, std::list, std::set ou mesmo std::string.

e sobre o free(), eu li que era má ideia usar ele, sendo melhor usar NULL


Se alguém disse isso, esse alguém está errado (ou então você não entendeu direito o que ele quis dizer). Eu já vi gente dizer que seria uma boa prática forçar o ponteiro para NULL após usar free() (e mesmo disso eu discordo, pois me parece redundante e, portanto, inútil), mas nunca vi alguém dizer para usar apenas sobrescrita com NULL, pois isso seria simplesmente errado em C e em C++ (ainda que seja válido noutras linguagens, como talvez seja em Java ou C#).


... “Principium sapientiae timor Domini, et scientia sanctorum prudentia.” (Proverbia 9:10)


12. Re: alocação dinamica de memoria [RESOLVIDO]

Aterson lino
Atr

(usa openSUSE)

Enviado em 03/09/2019 - 18:10h

Obrigado pelos esclarecimentos!
Sobre o CppDroid, estou usando ele, porque é gratuito, eu não entendo c++, gostaria de usar c4droid, mas é pago!
Ainda sobre o malloc();
Eu preciso entender melhor seu funcionamento!
Por exemplo:

malloc(100 * sizeof(var[0]));

Eu estaria definindo 100 bytes ou apenas posições?



01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts