Dúvida em relação a alocação dinâmica e boas práticas de programação em C

1. Dúvida em relação a alocação dinâmica e boas práticas de programação em C

Osmund Saddler
Saddler

(usa Outra)

Enviado em 09/07/2019 - 10:01h

É verdade que é considerado uma má prática de programação C alocar memória em uma função e desalocar em outra função?

Tenho essa dúvida porque recentemente tive que fazer o uso deste recurso em um projeto que estou desenvolvendo sozinho e eu sinceramente não sei se foi uma boa abordagem ...

Segue os códigos abaixo para uma análise:


//trecho de código

struct art_properties{

int art;
int quote;
int art_color;
};



//trecho de código

static void handler(int num){

clear();
endwin();
init_scr();
}

int resize(int key){

struct sigaction new_action;
struct sigaction old_action;

new_action.sa_flags=0;
new_action.sa_handler=handler;

sigemptyset(&new_action.sa_mask);
sigaction(SIGWINCH, &new_action, &old_action);

return getmaxy(stdscr);
}

static size_t count_rows(const char *file_path){

size_t rows=0;
FILE *file=fopen(file_path, "r");

if(file!=NULL){

while(!feof(file)){

if(fgetc(file)=='\n'){

rows++;
}
}

fclose(file);
}

return rows;
}

struct art_properties *print_art(int y, struct art_properties *properties){

struct art_properties aux;
FILE *art_file=NULL, *quote_file=NULL;

size_t i=0;
char row_content[1025], str_quote[1025];

const char *arts[]={"obj/arts/art_001.txt", "obj/arts/art_002.txt",
"obj/arts/art_003.txt", "obj/arts/art_004.txt",
"obj/arts/art_005.txt", "obj/arts/art_006.txt",
"obj/arts/art_007.txt", "obj/arts/art_008.txt",
"obj/arts/art_009.txt", "obj/arts/art_010.txt"};

if(properties==NULL){

srand(time(NULL));

aux.art=rand()%9;
aux.art_color=rand()%7;
aux.quote=1+(rand()%count_rows("obj/quotes.txt"));

properties=malloc(sizeof(struct art_properties));

memcpy(properties, &aux, sizeof(struct art_properties));

}else{

memcpy(&aux, properties, sizeof(struct art_properties));
}

attron(COLOR_PAIR(aux.art_color) | A_BOLD);

art_file=fopen(arts[aux.art], "r");

if(art_file!=NULL){

for(i=0; i<count_rows(arts[aux.art]); i++){

fgets(row_content, 1025, art_file);

mvprintw(y+i, 1, "%s", row_content);
}

fclose(art_file);
}

quote_file=fopen("obj/quotes.txt", "r");

if(quote_file!=NULL){

if(aux.quote!=1){

for(int i=0; i!=aux.quote; i++){

fgets(str_quote, 1025, quote_file);
}

mvprintw(y+2+i, 1, "[GANADO QUOTE] - %s", str_quote);
}

fclose(quote_file);
}

attroff(COLOR_PAIR(aux.art_color) | A_BOLD);

return properties;
}

struct art_properties *free_art(struct art_properties *ptr){

free(ptr);

return NULL;
}




//trecho de código

case '0':

noecho();

do{

properties=print_art(1, properties);

attron(COLOR_PAIR(YELLOW) | A_BOLD);
mvprintw(y-1, 1, "[?] - Are you sure you want to quit Saddler [Y/n]?");
attroff(COLOR_PAIR(YELLOW) | A_BOLD);

key=getch();
y=resize(key);

clear();

switch(key){

case 'y':
case 'Y':

key='Y';

break;

case 'n':
case 'N':

key='N';

break;

default:

break;
}

}while(key!='Y' && key!='N');

properties=free_art(properties);

echo();

break;



-> "funcionando" -> https://imgur.com/a/n3C8n5F
_____________________________________________________________________________________________________________________________

Dúvida cabeluda: Se acima eu fiz mau uso da alocação dinâmica, qual seria uma abordagem alternativa para os códigos acima? Uma solução que não afete o objetivo secundário da função print_art()?

* Objetivo secundário da função print_art() -> Mater as propriedades da arte impressa no terminal mesmo que a janela seja redimensionada.
_____________________________________________________________________________________________________________________________

Peço desculpas a todos os membros desta comunidade por não postar todo o projeto, mas é que ele ainda não está 100% finalizado e eu também não quero ser zuado por outros programadores mais experiêntes por postar "gambiarra" de 3000 linhas cheia de bugs.


  


2. Re: Dúvida em relação a alocação dinâmica e boas práticas de programação em C

Osmund Saddler
Saddler

(usa Outra)

Enviado em 10/07/2019 - 19:50h

OBS: Essa pergunta também foi postada em Portugal a Programar

https://www.portugal-a-programar.pt/forums/topic/77592-d%C3%BAvida-em-rela%C3%A7%C3%A3o-a-aloca%C3%A...



3. Re: Dúvida em relação a alocação dinâmica e boas práticas de programação em C

Osmund Saddler
Saddler

(usa Outra)

Enviado em 10/07/2019 - 22:36h

EDIT: Códico para testes:


#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <ncurses.h>

struct art_properties{

int art;
int quote;
int art_color;
};

static void init_scr(void){

if(initscr()==NULL){

fprintf(stderr, "[X] - initscr() == NULL!\n");

exit(EXIT_FAILURE);
}

if(has_colors()!=TRUE){

endwin();

fprintf(stderr, "[X] - Your terminal does not suport colors!\n");

exit(EXIT_FAILURE);

}else{

int bkg_color;

signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);

cbreak();
noecho();
keypad(stdscr, TRUE);

start_color();

if(use_default_colors()==OK){

bkg_color=-1;

}else{

bkg_color=COLOR_BLACK;
}

init_pair(RED, COLOR_RED, bkg_color);
init_pair(BLUE, COLOR_BLUE, bkg_color);
init_pair(CYAN, COLOR_CYAN, bkg_color);
init_pair(GREEN, COLOR_GREEN, bkg_color);
init_pair(WHITE, COLOR_WHITE, bkg_color);
init_pair(YELLOW, COLOR_YELLOW, bkg_color);
init_pair(MAGENTA, COLOR_MAGENTA, bkg_color);

refresh();
}
}

static void handler(int num){

clear();
endwin();
init_scr();
}

static int resize(void){

struct sigaction new_action;
struct sigaction old_action;

new_action.sa_flags=0;
new_action.sa_handler=handler;

sigemptyset(&new_action.sa_mask);
sigaction(SIGWINCH, &new_action, &old_action);

return getmaxy(stdscr);
}

static size_t count_rows(const char *file_path){

ssize_t rows=0;
FILE *file=fopen(file_path, "r");

if(file!=NULL){

while(!feof(file)){

if(fgetc(file)=='\n'){

rows++;
}
}

fclose(file);

}else{

rows=1;
}

return rows;
}

static struct art_properties *print_art(int y, struct art_properties *properties){

struct art_properties aux;
FILE *art_file=NULL, *quote_file=NULL;

size_t i=0;
char row_content[1025], str_quote[1025];

const char *arts[]={"arts/art_001.txt", "arts/art_002.txt",
"arts/art_003.txt", "arts/art_004.txt",
"arts/art_005.txt", "arts/art_006.txt",
"arts/art_007.txt", "arts/art_008.txt",
"arts/art_009.txt", "arts/art_010.txt"};

if(properties==NULL){

srand(time(NULL));

aux.art=rand()%9;
aux.art_color=1+(rand()%7);
aux.quote=1+(rand()%count_rows("quotes.txt"));

properties=malloc(sizeof(struct art_properties));

memcpy(properties, &aux, sizeof(struct art_properties));

}else{

memcpy(&aux, properties, sizeof(struct art_properties));
}

attron(COLOR_PAIR(aux.art_color) | A_BOLD);

art_file=fopen(arts[aux.art], "r");

if(art_file!=NULL){

for(i=0; i<count_rows(arts[aux.art]); i++){

fgets(row_content, 1025, art_file);

mvprintw(y+i, 1, "%s", row_content);
}

fclose(art_file);
}

quote_file=fopen("quotes.txt", "r");

if(quote_file!=NULL){

if(aux.quote!=1){

for(int i=0; i!=aux.quote; i++){

fgets(str_quote, 1025, quote_file);
}

mvprintw(y+2+i, 1, "[GANADO QUOTE] - %s", str_quote);
}

fclose(quote_file);

}else{

mvprintw(y+2+i, 1, "[GANADO QUOTE] - \"Te voy a matar!\"");
}

attroff(COLOR_PAIR(aux.art_color) | A_BOLD);

return properties;
}

static struct art_properties *free_art(struct art_properties *ptr){

free(ptr);

return NULL;
}

int main(void){

int key, y;
struct art_properties *properties=NULL;

init_scr();

y=getmaxy(stdscr);

do{

properties=print_art(1, properties);

attron(COLOR_PAIR(YELLOW) | A_BOLD);
mvprintw(y-1, 1, "[i] - Press Enter key to quit");
attroff(COLOR_PAIR(YELLOW) | A_BOLD);

key=getch();
y=resize();

}while(key!=10);

properties=free_art(properties);

endwin();

return EXIT_SUCCESS;
}




4. Re: Dúvida em relação a alocação dinâmica e boas práticas de programação em C

Paulo
paulo1205

(usa Ubuntu)

Enviado em 11/07/2019 - 10:38h

Saddler escreveu:

É verdade que é considerado uma má prática de programação C alocar memória em uma função e desalocar em outra função?


Nunca ouvi falar disso. E, sendo um dos usos de ponteiros justamente o de permitir que objetos alocados numa parte do programa possam ser passados a outra parte, tal ideia se torna ainda mais estranha.

Fico curioso de saber de que fonte você ouviu isso.

Tenho essa dúvida porque recentemente tive que fazer o uso deste recurso em um projeto que estou desenvolvendo sozinho e eu sinceramente não sei se foi uma boa abordagem ...

Segue os códigos abaixo para uma análise:

//trecho de código
struct art_properties{
int art;
int quote;
int art_color;
};


//trecho de código
static void handler(int num){
clear();
endwin();
init_scr();
}

int resize(int key){


Você não usa o parâmetro key ao longo da função. Por que tê-lo, ent

    struct sigaction new_action;
struct sigaction old_action;

new_action.sa_flags=0;
new_action.sa_handler=handler;

sigemptyset(&new_action.sa_mask);
sigaction(SIGWINCH, &new_action, &old_action);

return getmaxy(stdscr);
}

static size_t count_rows(const char *file_path){
size_t rows=0;
FILE *file=fopen(file_path, "r");

if(file!=NULL){
while(!feof(file)){
if(fgetc(file)=='\n'){
rows++;
}
}

fclose(file);
}

return rows;
}

struct art_properties *print_art(int y, struct art_properties *properties){
struct art_properties aux;
FILE *art_file=NULL, *quote_file=NULL;

size_t i=0;
char row_content[1025], str_quote[1025];

const char *arts[]={"obj/arts/art_001.txt", "obj/arts/art_002.txt",
"obj/arts/art_003.txt", "obj/arts/art_004.txt",
"obj/arts/art_005.txt", "obj/arts/art_006.txt",
"obj/arts/art_007.txt", "obj/arts/art_008.txt",
"obj/arts/art_009.txt", "obj/arts/art_010.txt"};

if(properties==NULL){
srand(time(NULL));


Normalmente você só chama srand() uma vez ao longo da vida do programa. E uma forma de garantir isso é colocar essa chamada dentro de main(), e fora de qualquer laço de repetição.

Eu não sei quantas vezes esta função aqui será chamada. Mas se for mais de uma vez, então esse srand() nessa posição não é uma boa ideia.

        aux.art=rand()%9;
aux.art_color=rand()%7;


Escolha de cores me leva a crer que você deveria usar 8, em lugar de 7. A não ser que você queira evitar a cor cinza/branca. É o caso?

Existem várias implementações de rand()/srand(), mas a implementação tradicional tem uma baixa aleatoriedade dos bits de mais baixa ordem. Isso faz com que a operação de obtenção de resto para obter um valor limitado nem sempre seja muito boa, especialmente com divisores que sejam potências de 2 ou seus múltiplos.

Existem implementações melhores de rand()/srand(), que melhoram a qualidade dos números pseudo-aleatórios] (PRN, de pseudo random numbers) gerados, mas mesmo com um algoritmo não tão bom, é possível melhorar a aleatoriedade do valor final por meio do deslocamento dos bits mais altos do PRN para baixo. Uma forma de fazer isso é a seguinte.

  int color=(int)(((double)rand()/(1.0+(double)RAND_MAX))*8.0); 


        aux.quote=1+(rand()%count_rows("obj/quotes.txt")); 


De novo, não sei quantas vezes você vai invocar print_art(). Mas se for mais de uma, talvez fosse melhor você não contar a quantidade de linhas desse arquivo dentro da função, mas antes de ela ser chamada a primeira vez. Alternativamente, você poderia deixar dentro da função, mas atribuindo seu valor uma vez só, com o auxílio de variáveis locais, mas estáticas, conforme o exemplo abaixo.

void func(int arg1, char *arg2){
static int *p_quant_linhas=NULL; // Variável estática, inicializada apenas uma vez e com valor preservado ao longo de múltiplas chamadas a ‘func’.
if(!p_quant_linhas){
p_quant_linhas=malloc(sizeof *p_quant_linhas);
if(!p_quant_linhas){
perror("Erro de alocação de memória");
exit(1);
}
*p_quant_linhas=conta_linhas("arquivo");
}

// A partir deste ponto, ‘*p_quant_linhas’ terá a quantidade de linhas do arquivo.

// ...

int aux=1+(int)(((double)rand()/(1.0+(double)RAND_MAX))*(double)(*p_quant_linhas));

// ...

}


        properties=malloc(sizeof(struct art_properties));
memcpy(properties, &aux, sizeof(struct art_properties));


Nas duas operações acima, eu acho ruim o uso do nome do tipo como argumento de sizeof: além de mais verborrágico, dificulta a manutenção do código (caso algum dia, por qualquer razão, o tipo do ponteiro seja alterado, você teria de catar todas as ocorrências de operações sobre ele para fazer com que o tipo continue concordando).

Eu prefiro fazer de um modo que faça com que o compilador infira o tamanho a partir do tipo que já foi declarado para o próprio objeto que é alvo da operação.

properties=malloc(sizeof *properties);
memcpy(properties, &aux, sizeof *properties);


Mas, além disso, o caso acima ainda tem os seguintes pontos de atenção:

  • Alocações podem falhar. Então você deveria testar o valor de properties após a invocação de malloc(), para ter certeza de que é válido gravar dados na região para onde tal valor aponta.

  • Não é necessário usar memcpy() para copiar valores de estruturas do mesmo tipo. Você poderia ter dito simplesmente “*properties=aux;” (desde que properties aponte para um endereço válido, como acima mencionado).

    }else{
memcpy(&aux, properties, sizeof(struct art_properties));


Aqui também caberia simplificar: “aux=*properties;”.

    }

attron(COLOR_PAIR(aux.art_color) | A_BOLD);

art_file=fopen(arts[aux.art], "r");

if(art_file!=NULL){
for(i=0; i<count_rows(arts[aux.art]); i++){
fgets(row_content, 1025, art_file);
mvprintw(y+i, 1, "%s", row_content);
}
fclose(art_file);
}

quote_file=fopen("obj/quotes.txt", "r");

if(quote_file!=NULL){

if(aux.quote!=1){

for(int i=0; i!=aux.quote; i++){

fgets(str_quote, 1025, quote_file);
}

mvprintw(y+2+i, 1, "[GANADO QUOTE] - %s", str_quote);
}

fclose(quote_file);
}

attroff(COLOR_PAIR(aux.art_color) | A_BOLD);

return properties;
}

struct art_properties *free_art(struct art_properties *ptr){
free(ptr);
return NULL;


Eu não gosto muito desse jeito de fazer, porque você acaba tendo, na hora de usar a função, de colocar duas vezes o nome da variável ponteiro que será alterada pela desalocação (e.g. “ptr_atr=free_art(ptr_art);”.

Não é estritamente necessário alterar o valor de um ponteiro que acabou de ser desalocado para NULL. A única efetiva proteção que isso traz é impedir que o valor antigo do ponteiro possa ser abusado para tentar observar conteúdo que ainda possa existir na memória, o que não é grande coisa, pois o mesmo efeito poderia ser conseguido se houver outra variável ponteiro com o mesmo valor, o que não é tão raro de acontecer. Por isso mesmo, a função padrão free() não se dá ao trabalho de fazer isso.

Se você quiser realmente uma função de desalocação que force o ponteiro, seria mais confortável fazê-la da seguinte maneira.

void free_art(struct art_properties **ptr){
free(*ptr);
*ptr=NULL;
}


Com essa forma, você poderia invocá-la da seguinte maneira: “free_art(&ptr_art);”. Veja como ela é mais enxuta do que do outro jeito, referenciando a variável ponteiro uma só vez.

Entretanto, as duas versões fazem pouco mais do que servir de wrapper para free(), e parte desse pouco mais não é efetivamente útil. Assim sendo, por que não usar diretamente free()? Perceba que, ainda que a biblioteca padrão do C não o faça, em bibliotecas de uso muito comum, incluindo algumas do POSIX e SUS, diversas funções que fazem alocações de dados com finalidades específicas, tais como strdup(), getline(), asprintf(), entre outras, não têm função específica para desalocação, mas esperam que a desalocação seja feita com free(). Você é livre (sem trocadilho) para fazer o mesmo.

} 


//trecho de código

case '0':

noecho();

do{

properties=print_art(1, properties);

attron(COLOR_PAIR(YELLOW) | A_BOLD);
mvprintw(y-1, 1, "[?] - Are you sure you want to quit Saddler [Y/n]?");
attroff(COLOR_PAIR(YELLOW) | A_BOLD);

key=getch();


Você não mostrou a declaração de key. Um erro comum é a pessoa declarar variáveis que recebem caracteres e teclas como char. Espero que não seja o seu caso, mas fica a informação de que o tipo tem de ser int.

Quanto ao resto do código, achei a transformação de 'y' em 'Y' e de 'n' em 'N' muito extensa para pouco efeito. Dá para ser mais simples.

if(key>=0 && key<255){
unsigned char k=toupper(key);
if(k=='Y' || k=='N')
key=k;
}


    	y=resize(key);
clear();
switch(key){
case 'y':
case 'Y':
key='Y';
break;
case 'n':
case 'N':
key='N';
break;
default:
break;
}
}while(key!='Y' && key!='N');
properties=free_art(properties);
echo();
break;



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


5. Re: Dúvida em relação a alocação dinâmica e boas práticas de programação em C

Osmund Saddler
Saddler

(usa Outra)

Enviado em 13/07/2019 - 11:06h

paulo1205 escreveu:

Saddler escreveu:

É verdade que é considerado uma má prática de programação C alocar memória em uma função e desalocar em outra função?


Nunca ouvi falar disso. E, sendo um dos usos de ponteiros justamente o de permitir que objetos alocados numa parte do programa possam ser passados a outra parte, tal ideia se torna ainda mais estranha.

Fico curioso de saber de que fonte você ouviu isso.



Vi em algum forúm por aí, mas não lembro qual ...

paulo1205 escreveu:

Saddler escreveu:

Tenho essa dúvida porque recentemente tive que fazer o uso deste recurso em um projeto que estou desenvolvendo sozinho e eu sinceramente não sei se foi uma boa abordagem ...

Segue os códigos abaixo para uma análise:

//trecho de código
struct art_properties{
int art;
int quote;
int art_color;
};


//trecho de código
static void handler(int num){
clear();
endwin();
init_scr();
}

int resize(int key){


Você não usa o parâmetro key ao longo da função. Por que tê-lo, ent



Isso foi alterado no código de testes logo acima.

paulo1205 escreveu:

Saddler escreveu:



struct sigaction new_action;
struct sigaction old_action;

new_action.sa_flags=0;
new_action.sa_handler=handler;

sigemptyset(&new_action.sa_mask);
sigaction(SIGWINCH, &new_action, &old_action);

return getmaxy(stdscr);
}

static size_t count_rows(const char *file_path){
size_t rows=0;
FILE *file=fopen(file_path, "r");

if(file!=NULL){
while(!feof(file)){
if(fgetc(file)=='\n'){
rows++;
}
}

fclose(file);
}

return rows;
}

struct art_properties *print_art(int y, struct art_properties *properties){
struct art_properties aux;
FILE *art_file=NULL, *quote_file=NULL;

size_t i=0;
char row_content[1025], str_quote[1025];

const char *arts[]={"obj/arts/art_001.txt", "obj/arts/art_002.txt",
"obj/arts/art_003.txt", "obj/arts/art_004.txt",
"obj/arts/art_005.txt", "obj/arts/art_006.txt",
"obj/arts/art_007.txt", "obj/arts/art_008.txt",
"obj/arts/art_009.txt", "obj/arts/art_010.txt"};

if(properties==NULL){
srand(time(NULL));


Normalmente você só chama srand() uma vez ao longo da vida do programa. E uma forma de garantir isso é colocar essa chamada dentro de main(), e fora de qualquer laço de repetição.

Eu não sei quantas vezes esta função aqui será chamada. Mas se for mais de uma vez, então esse srand() nessa posição não é uma boa ideia.


Acho que você não analisou os códigos com atenção.


#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <ncurses.h>

struct art_properties{

int art;
int quote;
int art_color;
};

static void init_scr(void){

if(initscr()==NULL){

fprintf(stderr, "[X] - initscr() == NULL!\n");

exit(EXIT_FAILURE);
}

if(has_colors()!=TRUE){

endwin();

fprintf(stderr, "[X] - Your terminal does not suport colors!\n");

exit(EXIT_FAILURE);

}else{

int bkg_color;

signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);

cbreak();
noecho();
keypad(stdscr, TRUE);

start_color();

if(use_default_colors()==OK){

bkg_color=-1;

}else{

bkg_color=COLOR_BLACK;
}

init_pair(RED, COLOR_RED, bkg_color);
init_pair(BLUE, COLOR_BLUE, bkg_color);
init_pair(CYAN, COLOR_CYAN, bkg_color);
init_pair(GREEN, COLOR_GREEN, bkg_color);
init_pair(WHITE, COLOR_WHITE, bkg_color);
init_pair(YELLOW, COLOR_YELLOW, bkg_color);
init_pair(MAGENTA, COLOR_MAGENTA, bkg_color);

refresh();
}
}

static void handler(int num){

clear();
endwin();
init_scr();
}

static int resize(void){

struct sigaction new_action;
struct sigaction old_action;

new_action.sa_flags=0;
new_action.sa_handler=handler;

sigemptyset(&new_action.sa_mask);
sigaction(SIGWINCH, &new_action, &old_action);

return getmaxy(stdscr);
}

static size_t count_rows(const char *file_path){

ssize_t rows=0;
FILE *file=fopen(file_path, "r");

if(file!=NULL){

while(!feof(file)){

if(fgetc(file)=='\n'){

rows++;
}
}

fclose(file);

}else{

rows=1;
}

return rows;
}

static struct art_properties *print_art(int y, struct art_properties *properties){

struct art_properties aux;
FILE *art_file=NULL, *quote_file=NULL;

size_t i=0;
char row_content[1025], str_quote[1025];

const char *arts[]={"arts/art_001.txt", "arts/art_002.txt",
"arts/art_003.txt", "arts/art_004.txt",
"arts/art_005.txt", "arts/art_006.txt",
"arts/art_007.txt", "arts/art_008.txt",
"arts/art_009.txt", "arts/art_010.txt"};

if(properties==NULL){

srand(time(NULL));

aux.art=rand()%9;
aux.art_color=1+(rand()%7);
aux.quote=1+(rand()%count_rows("quotes.txt"));

properties=malloc(sizeof(struct art_properties));

memcpy(properties, &aux, sizeof(struct art_properties));

}else{

memcpy(&aux, properties, sizeof(struct art_properties));
}

attron(COLOR_PAIR(aux.art_color) | A_BOLD);

art_file=fopen(arts[aux.art], "r");

if(art_file!=NULL){

for(i=0; i<count_rows(arts[aux.art]); i++){

fgets(row_content, 1025, art_file);

mvprintw(y+i, 1, "%s", row_content);
}

fclose(art_file);
}

quote_file=fopen("quotes.txt", "r");

if(quote_file!=NULL){

for(int i=0; i!=aux.quote; i++){

fgets(str_quote, 1025, quote_file);
}

mvprintw(y+2+i, 1, "[GANADO QUOTE] - %s", str_quote);

fclose(quote_file);

}else{

mvprintw(y+2+i, 1, "[GANADO QUOTE] - \"Te voy a matar!\"");
}

attroff(COLOR_PAIR(aux.art_color) | A_BOLD);

return properties;
}

static struct art_properties *free_art(struct art_properties *ptr){

free(ptr);

return NULL;
}

int main(void){

int key, y;
struct art_properties *properties=NULL;

init_scr();

y=getmaxy(stdscr);

do{

properties=print_art(1, properties);

attron(COLOR_PAIR(YELLOW) | A_BOLD);
mvprintw(y-1, 1, " - Press Enter key to quit");
attroff(COLOR_PAIR(YELLOW) | A_BOLD);

key=getch();
y=resize();

}while(key!=10);

properties=free_art(properties);

endwin();

return EXIT_SUCCESS;
}


[i]srand()
só é chamado quando properties aponta NULL, ou seja, uma única vez.


if(properties==NULL){

srand(time(NULL));

aux.art=rand()%9;
aux.art_color=rand()%7;
aux.quote=1+(rand()%count_rows("quotes.txt"));

properties=malloc(sizeof(struct art_properties));

memcpy(properties, &aux, sizeof(struct art_properties));

}else{

memcpy(&aux, properties, sizeof(struct art_properties));
}



int main(void){

int key, y;
struct art_properties *properties=NULL;

init_scr();

y=getmaxy(stdscr);

do{

properties=print_art(1, properties);

attron(COLOR_PAIR(YELLOW) | A_BOLD);
mvprintw(y-1, 1, " - Press Enter key to quit");
attroff(COLOR_PAIR(YELLOW) | A_BOLD);

key=getch();
y=resize();

}while(key!=10);

properties=free_art(properties);

endwin();

return EXIT_SUCCESS;
}


paulo1205 escreveu:

Entretanto, as duas versões fazem pouco mais do que servir de [i]wrapper
para free(), e parte desse pouco mais não é efetivamente útil. Assim sendo, por que não usar diretamente free()? Perceba que, ainda que a biblioteca padrão do C não o faça, em bibliotecas de uso muito comum, incluindo algumas do POSIX e SUS, diversas funções que fazem alocações de dados com finalidades específicas, tais como strdup(), getline(), asprintf(), entre outras, não têm função específica para desalocação, mas esperam que a desalocação seja feita com free(). Você é livre (sem trocadilho) para fazer o mesmo.


Concordo que o uso direto de free() faria mais sentido, porém não no programa de 3000 linhas chio de bugs que eu estou escrevendo kkkk

Saddler escreveu:

//trecho de código

case '0':

noecho();

do{

properties=print_art(1, properties);

attron(COLOR_PAIR(YELLOW) | A_BOLD);
mvprintw(y-1, 1, "[?] - Are you sure you want to quit Saddler [Y/n]?");
attroff(COLOR_PAIR(YELLOW) | A_BOLD);

key=getch();



paulo1205 escreveu:

Você não mostrou a declaração de key. Um erro comum é a pessoa declarar variáveis que recebem caracteres e teclas como char. Espero que não seja o seu caso, mas fica a informação de que o tipo tem de ser int.



Usei int mesmo.

"Você não usa o parâmetro key ao longo da função. Por que tê-lo, ent"


int resize(int key){


Lembra?

paulo1205 escreveu:
Quanto ao resto do código, achei a transformação de 'y' em 'Y' e de 'n' em 'N' muito extensa para pouco efeito. Dá para ser mais simples.

if(key>=0 && key<255){
unsigned char k=toupper(key);
if(k=='Y' || k=='N')
key=k;
}



Por que não simplismente key=toupper(key)? Por que unsigned char?

___________________________________________________________________________________________________________________________________________

"The CIA thinks that I'm a drug dealer - but nah, I just don't like computers."
- Terry A. Davis, Creator of TempleOS



6. Re: Dúvida em relação a alocação dinâmica e boas práticas de programação em C

Paulo
paulo1205

(usa Ubuntu)

Enviado em 15/07/2019 - 15:52h

Saddler escreveu:

Normalmente você só chama srand() uma vez ao longo da vida do programa. E uma forma de garantir isso é colocar essa chamada dentro de main(), e fora de qualquer laço de repetição.

Eu não sei quantas vezes esta função aqui será chamada. Mas se for mais de uma vez, então esse srand() nessa posição não é uma boa ideia.


Acho que você não analisou os códigos com atenção.


Minha resposta anterior foi em cima da sua postagem original to tópico, na qual você só tinha apresentado trechos de código.

Mas a ideia central da minha resposta não muda: srand() geralmente sé deve ser chamado uma vez, e a melhor maneira de garantir isso é colocando-a logo no início da definição de main().

paulo1205 escreveu:

Você não mostrou a declaração de key. Um erro comum é a pessoa declarar variáveis que recebem caracteres e teclas como char. Espero que não seja o seu caso, mas fica a informação de que o tipo tem de ser int.


Usei int mesmo.

"Você não usa o parâmetro key ao longo da função. Por que tê-lo, ent"

int resize(int key){ 


Lembra?


Essa é outra função, apresentada por você, à parte, em outro trecho de código. O key declarado no escopo da função resize() (que você mesmo, depois, eliminou da função) não tem necessariamente relação com o outro key, declarado em outro escopo.

Por que não simplismente key=toupper(key)? Por que unsigned char?


Para ficar com o mesmo resultado que o código que você tinha feito, usando switch: você só alterava o valor de key em quatro casos específicos, e o meu código também.

Quanto ao unsigned char, realmente foi desnecessário, uma vez que eu coloquei um teste de se o valor de key estava na faixa de 0 a 255. Poderia ter sido int, e teria sido melhor se o fosse. Eis aí um exemplo de problema de manutenção de código: eu tinha começado a escrever aquele pequeno bloco de um outro jeito, sem o teste do valor de key,e por isso convertia key num unsigned char. Quando eu coloquei o teste, a conversão ficou redundante, mas eu esqueci de alterar o tipo da variável.


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