Ir ao conteúdo
  • Cadastre-se

C Programa de cadastro de produtos


Posts recomendados

Linguagem C

Uma estrutura para representar Produtos com os seguintes dados: Código, Descrição, Fornecedor, Quantidade, Preço de Venda e Preço de Compra. Crie um vetor para armazenar os dados de no máximo N produtos, sendo N informado previamente pelo usuário.

Implemente as seguintes funções:

a. Procedimento para imprimir na tela um menu de opções, conforme abaixo, o qual lê do usuário a opção informada e a retorna:

b. Se o usuário informou a opção 1 invoque uma função para ler as informações e cadastrar o produto;

c. Se o usuário informou a opção 2 invoque uma função para listar todos os produtos cadastrados;

d. Se o usuário informou a opção 3 implemente uma função que solicita o código do produto e o remove (lógica ou fisicamente, você escolhe) do vetor de produtos;

e. Se o usuário informou a opção 4 implemente uma função que receba os produtos cadastrados e salve-os em um arquivo texto chamado “produtos.txt”;

f. Se o usuário informou a opção 5 o programa deve ser encerrado.

Todas as funções acima devem ser invocadas a partir do programa (função)

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

  • 2 semanas depois...

@devair1010 Eu estou com problema na leitura da descrição e do fornecedor, se eu coloco os números usando virgula para separar o preço ele não lê corretamente a parte de descrição e fornecedor nem o preço de venda, ai vira uma bagunça e sai errado, porém se eu coloco com ponto ele lê corretamente. Queria saber como corrigir isso pra ele executar normalmente tanto com um quanto com o outro 

 

 

#include <stdio.h>
#include <string.h>
#include <locale.h>
#define MAX 80

int main(){

    int escolha,lin,col, total_prod=0,num_cadastro=0,zerar_col;
    int a = 0;

    float produtos[3][3], codigo;
    char descricao[50][50], fornecedor[50][50];


    char linha[MAX];
    FILE *pba;
    char *nome = "tarefa_Rodney.txt";

    while(escolha!=5){

    printf("Escolha uma das opções abaixo \n");
    printf("1-Cadastar produto \n");
    printf("2-listar todos os produtos \n");
    printf("3-Remover produto \n");
    printf("4-salvar produtos em arquivo texto \n");
    printf("5-Sair\n");
    scanf("%d", &escolha);

    switch(escolha){

        case 1:
            printf("Quantos produtos vai cadastrar? \n");
            scanf("%d",&num_cadastro);

            for (lin=0; lin<num_cadastro; lin++) {
                    total_prod++;
                for(col=0; col<4;) {
                    do{
                    printf("[%d]-[%d]Qual o codigo do produto? O codigo tem que ser diferente de 0 \n",lin, col);
                    scanf("%f",&produtos[lin][col]);
                    }while(produtos[lin][col] == 0);

                    col++;
                    do{
                    printf("[%d]-[%d]Qual a quantidade? a quantidade tem que ser diferente de 0 \n", lin, col);
                    scanf("%f",&produtos[lin][col]);
                    }while(produtos[lin][col]== 0);
                    col++;
                    printf("[%d]-[%d]Qual o preco de venda? \n", lin, col);
                    scanf("%f", &produtos[lin][col]);
                    col++;
                    printf("[%d]-[%d]Qual o preco de compra? \n", lin, col);
                    scanf("%f", &produtos[lin][col]);
                    col++;

                }
                    printf("Qual a descricao?\n");
                    scanf("%s",&descricao[lin]);

                    printf("Qual o fornecedor? \n");
                    scanf("%s", &fornecedor[lin]);

            }


            break;


        case 2:
            if(total_prod==0){
                printf("Não ha nenhum produto cadastrado\n");
                break;
            }

            for (lin=0; lin<num_cadastro; lin++){
                for (col=0; col<4;){
                printf("Codigo do produto m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                col++;
                printf("Quantidade m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                col++;
                printf("Preco de venda m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                col++;
                printf("Preco de compra m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                col++;
                }
                printf("Forncedor: %s\n",fornecedor[lin]);
                printf("Descricao: %s\n", descricao[lin]);
            }

        break;

        case 3:

            printf("Qual o codigo do produto?\n");
            scanf("%f", &codigo);

                for(lin=0; lin<num_cadastro; lin++){
                        zerar_col=lin;
                    for(col=0; col<4; col++){
                        if(codigo==produtos[lin][col]){

                                for(col=0; col<4; col++){
                                    produtos[zerar_col][col] = 0;

                                }
                            strcpy(fornecedor[zerar_col], " ");
                            strcpy(descricao[zerar_col], " ");

                            total_prod= total_prod - 1;
                            break;
                        }else{
                        printf("produto nao encontrado\n");
                        break;
                        }

                    }

                }
        break;

        case 4:
            if((pba=fopen(nome,"w+")) == NULL){
               printf ("\n\nNao foi possivel abrir o arquivo.\n\n");
               return 1;
            }

             for(lin=0; lin<num_cadastro; lin++){
                    for(col=0; col<4; col++){
                        fprintf(pba,"Codigo do produto m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                        col++;
                        fprintf(pba,"Quantidade m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                        col++;
                        fprintf(pba,"Preco de venda m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                        col++;
                        fprintf(pba,"Preco de compra m[%d][%d] = %.2f \n", lin, col, produtos[lin][col]);
                        col++;
                    }
                    fprintf(pba,"Descricao produto: %s\n", descricao[lin]);
                    fprintf(pba, "Fornecedor: %s\n", fornecedor[lin]);
             }

             fclose(pba); // fecha arquivo
             printf("\nArquivo %s gravado com sucesso!\n", nome);
             return 0;


        case 5://teste
            printf("Obrigado por usar este programa");
        break;

    }

}

}

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

@Rodney Junior    para usar tanto virgula como ponto , precisa fazer uma verificação do que foi digitado ,  e você pode pegar uma string pois elas aceitam qualquer caractere e depois converter essa string para float com o comando atof , e poderia ser assim :

// funcao converte string para float
float str_to_float(char prod[16])
{
    for (int i = 0; i < strlen(prod); i++)
        if (prod[i] == ',')
            prod[i] = '.';
    return atof(prod);
}
//-----------------------------------------------------------
switch (escolha)
{
    case 1:
        printf("Quantos produtos vai cadastrar? \n");
        scanf("%d", &num_cadastro);
        for (lin = 0; lin < num_cadastro; lin++)
        {
            total_prod++;
            char prod[16];
            for (col = 0; col < 4;)
            {
                do
                {
                    printf("[%d]-[%d]Qual o codigo do produto? O codigo tem que ser diferente de 0 \n", lin, col);
                    scanf("%s", prod);
                    while (char c = fgetc(stdin) != '\n');    // limpar o buffer do teclado
                    produtos[lin][col] = str_to_float(prod);  // converte string para float
                } while (produtos[lin][col] == 0);
                col++;
                do
                {
                    printf("[%d]-[%d]Qual a quantidade? a quantidade tem que ser diferente de 0 \n", lin, col);
                    scanf("%s", prod);
                    while (char c = fgetc(stdin) != '\n');    // limpar o buffer do teclado
                    produtos[lin][col] = str_to_float(prod);  // converte string para float
                } while (produtos[lin][col] == 0);
                col++;
                printf("[%d]-[%d]Qual o preco de venda? \n", lin, col);
                scanf("%s", prod);
                while (char c = fgetc(stdin) != '\n');    // limpar o buffer do teclado
                produtos[lin][col] = str_to_float(prod);  // converte string para float
                col++;
                printf("[%d]-[%d]Qual o preco de compra? \n", lin, col);
                scanf("%s", prod);
                while (char c = fgetc(stdin) != '\n');   // limpar o buffer do teclado
                produtos[lin][col] = str_to_float(prod); // converte string para float
                col++;
            }
            printf("Qual a descricao?\n");
            scanf("%s", &descricao[lin]);
            printf("Qual o fornecedor? \n");
            scanf("%s", &fornecedor[lin]);
        }
        break;
    
    

 

Link para o comentário
Compartilhar em outros sites

2 horas atrás, Rodney Junior disse:

 Eu estou com problema na leitura da descrição e do fornecedor, se eu coloco os números usando virgula para separar o preço ele não lê corretamente a parte de descrição e fornecedor nem o preço de venda, ai vira uma bagunça e sai errado, porém se eu coloco com ponto ele lê corretamente. Queria saber como corrigir isso pra ele executar normalmente tanto com um quanto com o outro

Se o seu sistema operacional estiver configurado para português e só você usar a função setlocale.

Exemplo

	setlocale(LC_ALL, "");

Vai configurar o programa para aceitar a região atual do sistema.

 

É o seu programa está muito mal organizado, e eu acho que está saindo fora do enunciado.

Aqui está pedindo para fazer uma função que sirva como menu.

Em 04/05/2021 às 00:33, Rodney Junior disse:

a. Procedimento para imprimir na tela um menu de opções, conforme abaixo, o qual lê do usuário a opção informada e a retorna:

Você escreveu o menu direto na função main() eu acho que está errado.

 

Eu recomendo você começar de novo!

Spoiler

Ninguém faz isso, eu acho que é um esforço desnecessário da minha parte (;一_一)

 

Um exemplo inicial de como seria o programa seguindo o enunciado.

Exemplo no replit

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

@Rodney Junior seu programa está muito complicado e sequer atende ao enunciado ainda.

 

Escreva em torno dos dados.

 

Se o enunciado começa em 

 

Linguagem C

Uma estrutura para representar Produtos com os seguintes dados:
Código, Descrição, Fornecedor, Quantidade, Preço de Venda e Preço de Compra. 
  Crie um vetor para armazenar os dados de no máximo N produtos, 
  sendo N informado previamente pelo usuário.

Implemente as seguintes funções:

a. Procedimento para imprimir na tela um menu de opções, conforme abaixo,
o qual lê do usuário a opção informada e a retorna:

b. Se o usuário informou a opção 1 invoque uma função
  para ler as informações e cadastrar o produto;

c. Se o usuário informou a opção 2 invoque uma função para listar
  todos os produtos cadastrados;

d. Se o usuário informou a opção 3 implemente uma função que solicita
  o código do produto e o remove
  (lógica ou fisicamente, você escolhe) do vetor de produtos;

 

Como pode seu programa:

  • não ter a estrutura
  • não ter o vetor
  • não ter as funções
  • ter esse tamanho todo

???

 

Sobre o ponto decimal em Windows

 

controle-regional.thumb.png.500c6fac09bc12e22558bb14348574e3.png

 

 

 

No painel de controle do Windows tem a configuração do que é o ponto decimal para o sistema, e se pode usar qualquer coisa

 

 

Nesse caso aqui à esquerda está a vírgula como separador.

 

Isso é claro muito chato, porque programas que você escreve e planilhas e a calculadora tem uma noção de ponto decimal que pode ser diferente dessa aí do sistema.

 

E o Windows teve décadas de oportunidade por exemplo de fazer as teclas do teclado numérico seguirem a configuração do Windows e até hoje não conseguiu fazer.

 

É claro que a tecla do teclado numérico que tem o ponto decimal deveria ser SEMPRE o configurado no sistema  como ponto decimal, mas NUNCA foi possível configurar o óbvio no Windows: ao entrar com valores decimais usar a tecla PONTO do teclado numérico como seja lá o que estiver configurado no painel de controle. E, claro, quando tem a vírgula no teclado numérico usar o que estiver configurado no sistema como separador de decimais.

 

De volta ao tópico

 

Como saber qual o "ponto decimal" no Windows?

 

Chamando GetLocaleInfoEx() e pedindo pra ver o LOCALE_SDECIMAL

 

Como saber qual o ponto decimal em uso no seu programa C ou C++?

 

Chamando localeconv() e vendo o valor de decimal_point

 

Como saber se está certo, antes de ler valores?

 

Use um if. são duas letrinhas. 

 

Eis um exemplo do jeito oficial que mostra

(Windows) Local padrão para o usuario: pt-BR
Locale pt-BR (,)
Ponto decimal no sistema: [ , ]
Local atual reportado por setlocale(): C
Ponto decimal para esse programa: [ . ]
Mudando locale para "pt_BR"
Local atual reportado por setlocale(): pt_BR
Ponto decimal para esse programa: [ , ]

 

E o código C

//#define WINVER 0x0A00
//#define _WIN32_WINNT 0x0A00

#define BUFFER_SIZE 512
#include <stdio.h>
#include <locale.h>
#include <string.h>
#include <windows.h>
#include <winnls.h>


int         main(void)
{
    int res = 0;
    char ponto_decimal_programa = 0;
    char ponto_decimal_sistema = 0;

    // Windows: qual o locale padrão para o usuario
    //  e o ponto decimal em uso?

    WCHAR local[BUFFER_SIZE] = { 0 };
    res = GetUserDefaultLocaleName(local, BUFFER_SIZE);
    if (res <= 0)
    {
        wprintf( L"GetUserDefaultLocaleName() retornou erro %d\n",
            GetLastError());
        return -1;
    }
    wprintf(L"(Windows) Local padrão para o usuario: %s\n", local);

    // so um exemplo. nao precisa mesmo desse teste
    WCHAR wcBuffer[BUFFER_SIZE];
    res = GetLocaleInfoEx( local, LOCALE_SDECIMAL, wcBuffer, 0);
    if (res > BUFFER_SIZE)
    {
        printf("Buffer tem %d bytes, mas precisava de %d\n",
            BUFFER_SIZE, res);
        return -2;
    }

    res = GetLocaleInfoEx(
        local, LOCALE_SDECIMAL,
        wcBuffer, sizeof(wcBuffer)
    );
    if (res > 0)
    {
        wprintf(L"Locale %s (%s)\n", local, wcBuffer);
        ponto_decimal_sistema = (char) wcBuffer[0];
        printf("Ponto decimal no sistema: [ %c ]\n", ponto_decimal_sistema);
    }
    else
    {
        wprintf(L"GetLocaleInfoEx() %s Erro %d\n", local, GetLastError());
        return -3;
    }

    // C: qual o locale e o ponto decimal em uso?

    char    local_atual[BUFFER_SIZE] = { 0 };
    strcpy(local_atual, setlocale(LC_ALL, NULL));
    printf("Local atual reportado por setlocale(): %s\n", local_atual);

    struct lconv* locale_info_aqui = localeconv();
    printf("Ponto decimal para esse programa: [ %c ]\n", 
        *(locale_info_aqui->decimal_point) );

    printf("Mudando locale para \"pt_BR\"\n");
    printf("Local atual reportado por setlocale(): %s\n",
        setlocale(LC_ALL, "pt_BR"));
    locale_info_aqui = localeconv();
    printf("Ponto decimal para esse programa: [ %c ]\n",
        *(locale_info_aqui->decimal_point));

    return 0;
}

 

 

Considere sempre que os programas são escritos, no mundo real, para rodar nas máquinas de outras pessoas. Talvez as que pagaram pra você escrever :D então convém sempre ver como está tudo configurado.....

 

 

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

@Rodney Junior Nesse tipo de exercício geralmente se usa struct para armazenar os dados, a sua pode ser assim,

 

typedef struct{
    int codigo;
    char descricao[50];
    char fornecedor[50];
    int quantidade;
    float preco_venda;
    float preco_compra;
}Produto;

 

E para alocar a quantidade de produtos que serão cadastrados,

Produto *prod;
int n;

printf("Quantidade de produtos: ");
scanf("%d", &n);
prod = (Produto *)malloc(sizeof(Produto) * n);

 

O cadastro no loop do código p.ex,

printf("Codigo: ");
scanf("%d", &prod[i].codigo);

 

Link para o comentário
Compartilhar em outros sites

1 hora atrás, Midori disse:

Nesse tipo de exercício geralmente se usa struct para armazenar os dados

 

É verdade. Mas na prática é melhor escrever em torno dos dados e, vendo que um cadastro é que tem produtos dentro, escrever, ao invés de 

 

typedef struct{
    int codigo;
    char descricao[50];
    char fornecedor[50];
    int quantidade;
    float preco_venda;
    float preco_compra;
}Produto;
 

// E para alocar a quantidade de produtos que serão cadastrados,

Produto *prod;
int n;

 

Algo como

 


typedef struct
{
    int     codigo;
    char    descricao[50];
    char    fornecedor[50];
    int     quantidade;
    float   preco_venda;
    float   preco_compra;
}   Produto;


typedef struct 
{
    int         codigo;
    char*       nome;
    unsigned    N;
    Produto*    P;

}   Cadastro;

 

Que é muito mais flexível e deixa trivial usar vários cadastros no mesmo programa. É o conceito de encapsulamento.

 

Um programa assim

 

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

typedef struct
{
    int     codigo;
    char    descricao[50];
    char    fornecedor[50];
    int     quantidade;
    float   preco_venda;
    float   preco_compra;
}   Produto;


typedef struct 
{
    int         codigo;
    char*       nome;
    unsigned    N;
    Produto*    P;

}   Cadastro;

Cadastro*       cria(const unsigned tamanho, const char* nome);
Cadastro*       destroi(Cadastro* C);

int main(void)
{
    Cadastro    um;
    Cadastro    lojas[30];
    
    Cadastro*   loja_dois = cria( 3000, "Loja Monte Azul");
    loja_dois = destroi(loja_dois);

    return 0;
}

Cadastro*       cria(const unsigned N, const char* nm){ return NULL; };
Cadastro*       destroi(Cadastro* C){ return NULL; };

// fim

 

 

2 horas atrás, Midori disse:

printf("Quantidade de produtos: "); scanf("%d", &n); prod = (Produto *)malloc(sizeof(Produto) * n);

 

 

Teste SEMPRE o retorno de scanf(). Não há propósito prático em seguir com o programa e alocar N produtos se não leu o valor de N.

 

Mais ainda sendo um exercício porque o programa vai abortar logo em seguida.

 

Sendo um exercício é sempre saudável mostrar na tela o valor lido. Depois que o programa ficar pronto pode tirar isso. É bem melhor que o programa cancelar porque um valor que era pra ser pequeno foi lido como -252 por exemplo ;)

Programação defensiva, no caso.

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

Eu não sei se isso e alguma coisa do C++ ou porque eu ainda penso muito em pascal, mas pra mim não faz sentido tipificar uma estrutura.

typedef struct{
    int codigo;
    char descricao[50];
    char fornecedor[50];
    int quantidade;
    float preco_venda;
    float preco_compra;
}Produto;

Isso pra mim parece que meio que "oculta" o tipo, sendo que namespace de estruturas já são distintos de outros tipos de declaração em C.

 

outra coisa que eu acho estranho e fazer um cast quando está passando endereços(Ponteiros do tipo void) para ponteiros, o cast já não é automático? Ou em C++ e diferente?

prod = (Produto *)malloc(sizeof(Produto) * n);

Não seria melhor fazer assim?

prod = malloc(sizeof(*prod)*n);

Bem mais simples é claro.

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

4 minutos atrás, kgin disse:

Eu não sei se isso e alguma coisa do C++ ou porque eu ainda penso muito em pascal, mas pra mim não faz sentido tipificar uma estrutura.

O tópico é sobre C, mas como assim "tipificar estrutura"?

 

8 minutos atrás, kgin disse:

outra coisa que eu acho estranho e fazer um cast quando está passando endereços

Talvez você tenha razão e seja estranho, mas quando comecei a estudar a linguagem via exemplos em livros com cast. Embora eu não tenha visto warnings do compilador nas vezes que não usei.

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

5 minutos atrás, Midori disse:

O tópico é sobre C

Eu sei que é, mas tudo que eu vejo os outros postarem parece que vem do C++.

 

6 minutos atrás, Midori disse:

mas como assim "tipificar estrutura"?

Acabei inventando palavra.

seria criar uma sinônimo ou alias, porque você acabou de criar uma estrutura pra que dar um nome que foge do escopo do proposito do mesmo?

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

1 hora atrás, kgin disse:

Eu não sei se isso e alguma coisa do C++ ou porque eu ainda penso muito em pascal, mas pra mim não faz sentido tipificar uma estrutura

 

Isto é C e essa é uma estrutura anônima, @kgin

 

O nome estaria estaria depois da palavra struct e antes das chaves.

 

typedef struct{
    int codigo;
    char descricao[50];
    char fornecedor[50];
    int quantidade;
    float preco_venda;
    float preco_compra;
}Produto;

 

Do modo como @Midoriescreveu a struct não tem nome e isso é o comum. Um record em Pascal é um pouco diferente. Em C++ é também diferente ainda que seja uma struct, a mesma keyword

 

Porque se faz isso?

 

Extensivamente se usa isso porque

  • um typedef não aloca memória, apenas define um nome. Veja no programa exemplo que deixei acima o uso comum
  • E tem um aspecto muito claro na produção e legibilidade do código...
    • exemplo
       
      
      typedef struct st_cad
      {
          int         codigo;
          char*       nome;
          unsigned    N;
          Produto*    P;
      
      }   Cadastro;
      
      Cadastro*       cria(const unsigned tamanho, const char* nome);
      Cadastro*       destroi(Cadastro* C);
      
      Cadastro*       junta_S(Cadastro* um, Cadastro* outro){ return NULL; }
      struct st_cad*  junta_XL(struct st_cad* um, struct st_cad* outro){ return NULL; }

Entenda que junta_S() e junta_XL() são equivalentes. Mas qual será mais legível? Ainda mais considerando a convenção praticamente universal em C de escrever apenas a primeira letra em maiúscula para nomes de estruturas?

 

E qual o propósito de repetir struct em  TODA declaração de algum cadastro?

 

Esse é o propósito. Em C++ a declaração não cria nada. O construtor cria, como em C#, java, Python. Pascal não tem construtores, nem C.

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

11 minutos atrás, kgin disse:

seria criar uma sinônimo ou alias, porque você acabou de criar uma estrutura pra que dar um nome que foge do escopo do proposito do mesmo?

Não sei se entendi o que quer dizer com fugir do propósito.

 

Apenas defini a estrutura onde agrupei tudo no contexto dos produtos. Veja como começa o comentário no primeiro post,

Em 04/05/2021 às 00:33, Rodney Junior disse:

Uma estrutura para representar Produtos com os seguintes dados:

 

Eu poderia apenas ter criado a estrutura assim,

struct Produto{
...
};

 

Mas prefiro com typedef em vez de usar novamente struct na declaração. Sem typedef seria struct Produto prod.

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

35 minutos atrás, kgin disse:

outra coisa que eu acho estranho e fazer um cast quando está passando endereços(Ponteiros do tipo void) para ponteiros, o cast já não é automático? Ou em C++ e diferente?

 

Em C++ é diferente. É preciso especificar o tipo

 

O cast é automático, para o compilador e para o leitor. 

 

36 minutos atrás, kgin disse:

Não seria melhor fazer assim?


prod = malloc(sizeof(*prod)*n);

Bem mais simples é claro.

 

Não, não é mais claro.

 

Para o compilador tanto faz, mas para o leitor, mesmo o cara que escreveu o programa, ao ver apenas o que está na linha, sendo o cast implícito, deixa a possibilidade de o cara alocar uma coisa pensando em outra. O parâmetro de malloc é uma expressão que gera um número, nem sempre está claro a que se refere

 

	prod = malloc( define_valor(a,b,..) );
	param = malloc ( 324 * sizeof(int*) );

 

Vendo essas duas linhas acima não dá pra saber ao certo o que é o que. Imagine que
 

    struct 
    { 
        int coisas[2000];
    } Produto;

    struct 
    { 
      int c;
    } Parametro;

	struct Produto* prod;
	struct Parametro* param;

 

Se você deixar o tipo implícito isso pode esconder erros em que o desenvolvedor achava que estava alocando um tipo e era outro e o erro só vai aparecer depois. E isso custa tempo e dinheiro.
 

Agora se você ler assim...

	prod = (struct Produto*) malloc( define_valor(a,b,..) );
	param = (struct Parametro*) malloc ( 324 * sizeof(int*) );

 

Diminui muito a chance de erro. 

 

É como o 
 

Option Explicit On

 

do Visual Basic: você não precisa declarar nada. Mas isso quer dizer que se errar uma letra no nome no meio de um trecho complicado vai criar OUTRA variável.

 

E de onde vem esse lance de não  usar cast no malloc()

 

Vem dos anos 90, de discussões na antiga USENET e que passaram para uma compilação chama C_FAQ que virou referência. Só que no final do século passado. E mesmo lá no C FAQ e na Usenet na época já se alertava exatamente para o que expliquei acima: conversões implícitas não são assim uma beleza e podem mascarar erros e gerar mais probleams que soluções. Assim como em Visual Basic. 

 

Citação

Still later, with the coming of ANSI C, the type void * was introduced, malloc() was changed to return that type, and implicit pointer conversions went back into the language when void * was involved.

Therefore, the seemingly redundant casts are used by people who are

(a) concerned with portability to all pre-ANSI compilers, or

(b) of the opinion that implicit conversions are a bad thing. [Mark Brader]

 

(Direto do C FAQ.)

 

Entenda que isso é dos anos 90 e muita coisa mudou desde então.

 

E isso nunca foi atualizado.

 

 

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

2 horas atrás, Midori disse:

Eu poderia apenas ter criado a estrutura assim,

 

Mas prefiro com typedef em vez de usar novamente struct na declaração. Sem typedef seria struct Produto prod.

Concordo. 

 

Depois de tantas vezes escrevendo   struct   não diria que ler é irritante porque não tenho essa limitação, não torna o código menos legível porque as crianças entendem a declaração, e economizar caracteres no código-fonte é uma motivação bem específica, por exemplo: sistemas embarcados onde o disco é limitado.

 

Numa situação de exercício e este é caso,  usa-se   typedef   quando enunciado, senão simplesmente haja como mais preferir.

struct _sproduto {
                 /**< Membro da _sproduto */
};

struct _sproduto  shampoo_johnson= {/*...*/};

Eu prefiro   struct,

 

mas se o enunciado pedir que oculte com  typedef, eu  faço.

typedef struct {
                 /**< Membro da _sproduto */
} _sproduto;

  _sproduto  shampoo_johnson= {/*...*/};

 

Poderia também se me fosse pedido

typedef struct {
                 /**< Membro da _sproduto */
} SProduto;

  SProduto  shampoo_johnson= {/*...*/};

 

 

Enfim, sempre contemple o máximo de quesitos do enunciado.

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

1 hora atrás, mauro_b disse:

economizar caracteres no código-fonte é uma motivação bem específica, por exemplo: sistemas embarcados onde o disco é limitado

Código fonte não vai para sistemas embarcados. O código é gerado e transferido ou copiado para ROM que é instalada no sistema de destino. Se a arquitetura é diferente se usa o que se chama de cross-compiling, um compilador que gera código para uma arquitetura diferente daquela onde está instalado. O tamanho e quantidade de letrinhas no programa é irrelevante para o compilador, que vai criar o que se chama de tabela de símbolos e gerar o código usando os endereços e não os nomes...

 

E se testa em um emulador, que simula o sistema de destino no ambiente de desenvolvimento, por exemplo como se faz para escrever aplicativos para celular no Windows.

 

1 hora atrás, mauro_b disse:

não torna o código menos legível porque as crianças entendem a declaração

 

Nesse exemplo, do programa que deixei acima
 

Cadastro*       junta_S(Cadastro* um, Cadastro* outro){ return NULL; }
struct st_cad*  junta_XL(struct st_cad* um, struct st_cad* outro){ return NULL; }

 

as funções junta_S() e junta_XL() são a mesma coisa. E uma busca nos milhares de repositórios de código C opensource de código vai mostrar que praticamente nunca se usa a segunda opção. 

 

E acho difícil concluir que a primeira não é mais legível...

 

E quando a estrutura não é anônima mesmo assim um typedef é criado.

 

Exemplo: o buffer da console em consoleapi2.h no Windows moderno: 
 

typedef struct _CONSOLE_SCREEN_BUFFER_INFOEX {
    ULONG cbSize;
    COORD dwSize;
    COORD dwCursorPosition;
    WORD wAttributes;
    SMALL_RECT srWindow;
    COORD dwMaximumWindowSize;
    WORD wPopupAttributes;
    BOOL bFullscreenSupported;
    COLORREF ColorTable[16];
} CONSOLE_SCREEN_BUFFER_INFOEX, *PCONSOLE_SCREEN_BUFFER_INFOEX;

 

Essa estrutura é básica para manipular a console no Windows. Note que a struct tem um '_' na frente do nome. Ninguém usa.

 

Exemplo: a informação sobre a fonte em uso na consoleapi3.h no Windows moderno: 
e

typedef struct _CONSOLE_FONT_INFOEX {
    ULONG cbSize;
    DWORD nFont;
    COORD dwFontSize;
    UINT FontFamily;
    UINT FontWeight;
    WCHAR FaceName[LF_FACESIZE];
} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;


Acho difícil concluir que a primeira não é mais legível que a segunda. O código gerado é claro o mesmo. Note que a struct tem também um '_' na frente do nome. Ninguém usa.

 

Exemplo:

 

Veja no github https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples onde tem muito código em C escrito por aquela empresa que escreveu o Windows e esses headers todos e veja como praticamente SEMPRE se usa a versão typedef e NUNCA a struct.

 

1 hora atrás, mauro_b disse:

mas se o enunciado pedir que oculte com  typedef, eu  faço.

 

Como eu expliquei, typedef pode "ocultar" o fato de ser o typedef estar criando um tipo estruturado ou não. Apenas isso. A estrutura é chamada (pelo compilador) de anônima --- unnamed --- nesse caso
 

typedef struct {
                 /**< Membro da _sproduto */
} _sproduto;

  _sproduto  shampoo_johnson= {/*...*/};

 

por exemplo veja
 

image.png.71e03d880e0d6f3d2d196994006ec837.png

 

 

 

 

 

no IDE Visual Studio

 

 

 

 

 

Ou image.png.0883d63c75734b00c3d29133cbcb5b00.png

 

 

No Visual Studio Code

 

 

 

 

 

 

 

 

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

1 hora atrás, arfneto disse:

Código fonte não vai para sistemas embarcados. O código é gerado e transferido ou copiado para ROM que é instalada no sistema de destino. Se a arquitetura é diferente se usa o que se chama de cross-compiling, um compilador que gera código para uma arquitetura diferente daquela onde está instalado. O tamanho e quantidade de letrinhas no programa é irrelevante para o compilador, que vai criar o que se chama de tabela de símbolos e gerar o código usando os endereços e não os nomes...

 

E se testa em um emulador, que simula o sistema de destino no ambiente de desenvolvimento, por exemplo como se faz para escrever aplicativos para celular no Windows.

 

 

Eu não tenho experiência com essa categoria de sistema, foi um exemplo que agora se nota equivocado  quando quis exemplificar um computador tão limitado que economizar caracteres no código-fonte é uma justificativa razoável nessa situação hipotética de um disco pequeno.

 

 

1 hora atrás, arfneto disse:

Nesse exemplo, do programa que deixei acima

 

as funções junta_S() e junta_XL() são a mesma coisa. E uma busca nos milhares de repositórios de código C opensource de código vai mostrar que praticamente nunca se usa a segunda opção. 

 

E acho difícil concluir que a primeira não é mais legível...

 

Na sua opinião,   já eu penso que a escolha do identificador na "segunda  opção" é que é RUIM   st_cad  é mais que ruim...  é podre rsrsr.

 

 

 

1 hora atrás, arfneto disse:

Como eu expliquei, typedef pode "ocultar" o fato de ser o typedef estar criando um tipo estruturado ou não. Apenas isso. A estrutura é chamada (pelo compilador) de anônima --- unnamed --- nesse caso

Tudo que preciso saber sobre  o recurso tem aqui: https://en.wikipedia.org/wiki/Typedef

 

 

1 hora atrás, arfneto disse:

Acho difícil concluir que a primeira não é mais legível que a segunda. O código gerado é claro o mesmo. Note que a struct tem também um '_' na frente do nome. Ninguém usa.

 

 

Porque não querem usar, porque foi pedido para ser assim... porque estão acostumados... porque é uma cultural e dependendo da circunstância não há escolha. 

 

Estás esperando que digamos o quê?

Isso não torna mais legível, só oculta algumas coisas.

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

3 horas atrás, mauro_b disse:

Na sua opinião,   já eu penso que a escolha do identificador na "segunda  opção" é que é RUIM   st_cad  é mais que ruim...  é podre rsrsr.

 

 

Então @mauro_b você acha que dessas duas
 

Cadastro*       junta_S(Cadastro* um, Cadastro* outro){ return NULL; }
struct st_cad*  junta_XL(struct st_cad* um, struct st_cad* outro){ return NULL; }

 

A segunda é mais legível? ok

 

Em relação a st_cad entenda que estou dizendo que é prática comum usar estruturas anônimas e deixei exemplo que pode compilar e mostrei que o compilador a vê assim, anônima --- unnamed.

 

Ou seja, não usar nome algum. A exceção óbvia é quando a estrutura tem uma auto-referência, como é o caso de listas ligadas por exemplo algo assim:

 


typedef struct st_node
{
	void*		    Data;
	struct st_node*	next;
	struct st_node*	prev;

}   Node;

 

E assim o nome só vai ser usado aí dentro para o compilador entender a referência. Isso está no padrão ISO.

 

Em relação ao prefixo que o usuário achou "pobre" não há muito que dizer: quando é preciso usar se usa o que o patrão convenciona. Sim, patrão e não padrão: muitas empresas e mesmo escolas tem convenções de nomenclatura e guias de boas práticas e seguir não é uma opção, apenas  o único caminho.

 

Eu escrevi umas coisas para um banco, tempos atrás, aqui no BR, onde era obrigatório prefixar os nomes de estruturas exatamente com st_ e os tipos com t_ e mais uma cartilha de coisas de que não me lembro. Não me ocorreu na época discutir isso com eles ou dizer que era "podre" mas acho que não me serviria de nada :) Qualquer trecho de programa que fosse flagrado não-conforme à cartilha seria rejeitado na revisão de código e não faria bem para o perfil do desenvolvedor ou para o bonus no final de ano... E é assim em geral. Muitas vezes até o número máximo de colunas do programa e de níveis de if é determinado. 

 

Se leu o artigo que referenciou talvez saiba que em muitas bibliotecas se usa o sufixo _t para tipos. Outras usam o prefixo m_ para variáveis membro (mais comum em java) e assim segue a vida.

 

No entanto em relação a esse trecho de seu exemplo

 

6 horas atrás, mauro_b disse:

Poderia também se me fosse pedido

 

typedef struct {
                 /**< Membro da _sproduto */
} _sproduto;

  _sproduto  shampoo_johnson= {/*...*/};

 

Isso provavelmente não passaria em lugar algum, porque o uso de prefixos  '_' e "__" é reservado para as bibliotecas e assim quase sempre é proibido, mesmo sendo em um código com escopo local --- ordinary namespace como diz no Standard.

 

Do C ISO International Standard online (2011)

 

7.1.3 Reserved identifiers
1 Each header declares or defines all identifiers listed in its associated subclause, and
optionally declares or defines identifiers listed in its associated future library directions
subclause and identifiers which are always reserved either for any use or for use as file
scope identifiers.
 All identifiers that begin with an underscore and either an uppercase letter or another
underscore are always reserved for any use.
 All identifiers that begin with an underscore are always reserved for use as identifiers
with file scope in both the ordinary and tag name spaces

 

Então o simples é: nunca use isso.

 

3 horas atrás, mauro_b disse:

Tudo que preciso saber sobre  o recurso tem aqui

 

Cuidado ao tomar a wikipedia como referência. Qualquer pode escrever lá e até alguém corrigir ou introduzir outro erro ou forçar uma tendência ou opinião pessoal pode levar uns dias. 

 

Para tudo o que quer saber sugiro recorrer aos padrões e ao imenso volume de código disponível em C online.

 

3 horas atrás, mauro_b disse:

Estás esperando que digamos o quê?

Isso não torna mais legível, só oculta algumas coisas

 

Está bem. A crença é livre. Não espero nada. Só mostrei dados e argumentos. Não é minha opinião: está em toda parte.

 

Por exemplo a Microsoft usa muito isso

 

typedef struct _CONSOLE_FONT_INFOEX {
    ULONG cbSize;
    DWORD nFont;
    COORD dwFontSize;
    UINT FontFamily;
    UINT FontWeight;
    WCHAR FaceName[LF_FACESIZE];
} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;

 

Um underscore para indicar a struct e o nome para usar o typedef, que como eu disse é o que todo mundo vai usar, inclusive a Microsoft na imlementação.

 

Só que eles são os implementadores. Para eles é reservadoo tal underscore e o duplo underscore. Espero que tenha entendido.

 

 

 

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

56 minutos atrás, arfneto disse:

Então @mauro_b você acha que dessas duas
A segunda é mais legível? ok

kkkkkkkkkkkkkkkkkkk

 

A segunda é ruim não devido à palavra-chave   struct   ,  mas sim por escolha ruim de identificador

Não há diferença, além de ocultar coisa.

       Cadastro*       unta_S(        Cadastro* um,        Cadastro* outro){ return NULL; }
struct Cadastro*      junta_XL(struct Cadastro* um, struct Cadastro* outro){ return NULL; }

 

56 minutos atrás, arfneto disse:

Isso provavelmente não passaria em lugar algum, porque o uso de prefixos  '_' e "__" é reservado para as bibliotecas e assim quase sempre é proibido, mesmo sendo em um código com escopo local --- ordinary namespace como diz no Standard.

 

Concordo!

 

Daí, digo...

8 horas atrás, mauro_b disse:

Poderia também se me fosse pedido



typedef struct {
                 /**< Membro da _sproduto */
} SProduto;

  SProduto  shampoo_johnson= {/*...*/};

 

Enfim, sempre contemple o máximo de quesitos do enunciado.

 

 

Ainda poderia escrever assim:

typedef struct Produto {
                 /**< Membro da _sproduto */
} SProduto;

  SProduto  shampoo_johnson= {/*...*/};

 

Se me pendem para fazer eu faço de todas as formas que precisar.

Mas prefiro com  struct   _sNome_da_estrutura.

 

 

JAMAIS nomear assim:  st_cad

A menos que tenha uma motivação muito séria para economizar caracteres.

 

56 minutos atrás, arfneto disse:

Cuidado ao tomar a wikipedia como referência. Qualquer pode escrever lá e até alguém corrigir ou introduzir outro erro ou forçar uma tendência ou opinião pessoal pode levar uns dias. 

 

Para tudo o que quer saber sugiro recorrer aos padrões e ao imenso volume de código disponível em C online.

 

 

Então é caso de você ir à página e editar com suas fontes? Seria bem mais significativo do que alertas.

Por enquanto essa é mais uma fonte para informação do   typedef.

 

Se encontrou algum erro faça o favor de corrige-lo,

afinal "qualquer pode escrever lá" :)

 

Outra fonte typedef: https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html#The-typedef-Statement

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

1 hora atrás, mauro_b disse:

Então é caso de você ir à página e editar com suas fontes? Seria bem mais significativo do que alertas.

Por enquanto essa é mais uma fonte para informação do   typedef.

 

Se encontrou algum erro faça o favor de corrige-lo,

afinal "qualquer pode escrever lá"

 

Vejo que entendeu o que eu disse. 

 

O que eu escrevi aqui já é muito para meu tempo. Citei o ISO standard, os links, mostrei trechos de bibliotecas oficiais da Microsoft, expliquei o porque do que estou falando o que. Dei contra-exemplos  e deixei código compilável.

 

A fonte definitiva é o padrão ISO. O uso cotidiano pode ser visto onde eu mostrei e em toda parte. Boa parte do software do planeta é escrita em C afinal.

 

 

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

36 minutos atrás, arfneto disse:

 

Vejo que entendeu o que eu disse. 

 

O que eu escrevi aqui já é muito para meu tempo. Citei o ISO standard, os links, mostrei trechos de bibliotecas oficiais da Microsoft, expliquei o porque do que estou falando o que. Dei contra-exemplos  e deixei código compilável.

 

A fonte definitiva é o padrão ISO. O uso cotidiano pode ser visto onde eu mostrei e em toda parte. Boa parte do software do planeta é escrita em C afinal.

 

 

 

Ah!!!

 

Uma página do  calibre da Wikipedia tem seus revisores de conteúdo, eles sabem qual é a fonte definitiva. Repito se discorda de algo que está escrito no artigo então encaminhe uma revisão, se puder.

 

 

36 minutos atrás, arfneto disse:

O que eu escrevi aqui já é muito para meu tempo. Citei o ISO standard, os links, mostrei trechos de bibliotecas oficiais da Microsoft, expliquei o porque do que estou falando o que. Dei contra-exemplos  e deixei código compilável.

 

Contra-exemplo/???

 

2 horas atrás, arfneto disse:

Cadastro*       junta_S(Cadastro* um, Cadastro* outro){ return NULL; }
struct st_cad*  junta_XL(struct st_cad* um, struct st_cad* outro){ return NULL; }

 

 

A uma estrutura  com bom nome, e outra (segunda) com nome RUIM, que em nada tem a ver com uso da palavra   struct.

Se o enunciado do exercício pede explicitamente que use  typedef então usamos,  senão é facultativo usa quem quiser pelas razões quaisquer que sejam: mas torna o código mais legível retirando  struct   não é uma delas.

 

Com struct é assim:  st_cad

Sem struct é assim: Cadastro

Se pensa que eu vou ensinar isso para adolescente ainda no fundamental? :D

 

 

 

Porém, mais simples é  porque simplifica a declaração,

foi nessa parte que concordei.

11 horas atrás, Midori disse:

Apenas defini a estrutura onde agrupei tudo no contexto dos produtos. Veja como começa o comentário no primeiro post,

Em 04/05/2021 às 00:33, Rodney Junior disse:

Uma estrutura para representar Produtos com os seguintes dados:

 

Eu poderia apenas ter criado a estrutura assim,


struct Produto{
...
};

 

Mas prefiro com typedef em vez de usar novamente struct na declaração. Sem typedef seria struct Produto prod.

 

  • Curtir 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...