Language C - Understanding the Concept of Pointers and Dynamic Allocation, where is the error?

Asked

Viewed 59 times

3

I would like a help in pointer call concepts, and dynamic allocation with struct.

I’m developing a code to address an issue of college work, and I’m coming across some errors that I believe are conceptual, but I’m not getting around to solving them. Someone could give me a light?

I didn’t know that there was a restriction of aid in a programming community, either due to language, so maybe this request for help could be duplicated.

My problem is basically in the function that I create the "report" of the registered actions, the compiler does not return all the registered information besides returning an error message from . dll (sic!)

Follows the code:

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

#define MAX 100
#define QACOES 5

struct Data 
{
    int dia;
    int mes;
    int ano;
};

struct bvalores
{
    char codigoAcao[5];
    char areaAtuacao[MAX];
    struct Data data;
    float valorAbertura = 0;
    float valorFechamento = 0;
    double variAcao;
};

struct bvalores* acoes[QACOES];
int contador;

//recebe os dados digitados pelo usuário
void registros(struct bvalores* acoes)
{
    setlocale(LC_ALL, "Portuguese");

    printf_s("Digite o código da ação: ");
    scanf_s("%s", &acoes->codigoAcao, 5);
    printf_s("Digite a área de atuação da empresa: ");
    scanf_s("%s", &acoes->areaAtuacao, MAX);
    printf_s("Qual o valor de aberta: ");
    scanf_s("%f", &acoes->valorAbertura);
    printf_s("Qual o valor de fechamento: ");
    scanf_s("%f", &acoes->valorFechamento);

    acoes->variAcao = (acoes->valorAbertura - acoes->valorFechamento) / acoes->valorAbertura;
    acoes->variAcao *= 100;

    printf("Data de lançamento: ");
    scanf_s("%d / %d / %d", &acoes->data.dia, &acoes->data.mes, &acoes->data.ano);
}

//registra cada ação com seus respectivos dados em uma posição da memória
void novoregistro()
{
    setlocale(LC_ALL, "Portuguese");

    if (contador < QACOES)
    {
        *(acoes + contador) = (struct bvalores*)malloc(1 * sizeof(struct bvalores));
        registros(acoes[contador]);
        contador++;
    }
    else
    {
        printf_s("Só é possível 5 registros. Limite excedido");
    }
}

char menu()
{
    setlocale(LC_ALL, "Portuguese");

    printf_s("\n");
    printf_s("Digite [I] para incluir um novo registro: \n");
    printf_s("Digite [R] para visualizar a variação das ações registradas: \n");
    printf_s("Digite [S] para sair do programa: \n");

    printf_s("\nQual a opção desejada: ");

    int opcao = getchar();
    int c;

    while ((c = getchar()) != '\n' && c != EOF)
    {
        opcao = c;
    }
    return opcao;   
}

//função que monta um relatório dos registro das açoes
void relatorio()
{
    setlocale(LC_ALL, "Portuguese");
    struct bvalores* acao;

    for (int i = 0; i <= contador; i++)
    {
        acao = *(acoes + i);
        printf_s("Ação da bolsa: %s  -  Area de atuação: %s\n", acao->codigoAcao, acao->areaAtuacao);
        printf_s("Data da operação: %d/%d/%d\n", acao->data.dia, acao->data.mes, acao->data.ano);
        printf_s("\n");
        printf_s("Valor de abertura: R$ %.2f  -  Valor de fechamento: R$ %.2f\n", acao->valorAbertura, acao->valorFechamento);
        printf_s("Variãção do dia: %.2f%%", acao->variAcao);
        printf_s("\n");
    }
}

int main()
{
    char sopcao;

    do 
    {
        sopcao = menu();
        switch (sopcao)
        {
        case 'i':
        case 'I':
            novoregistro();
            break;

        case 'R':
        case 'r':
            relatorio();
            break;

        default:
            printf_s("Opção invalida");
            break;
        }
    } while (sopcao != 'S' && sopcao != 's');   

    system("pause");
    return 0;
}
  • You did not assign an initial value to the variable contador before using it.

  • 1

    Welcome to the Sopt. Our goal is to form a repository of questions and answers useful to several users so that one can find an answer through the search engine, either the one embedded in the site or a search engine like Google. There is no restriction of the language as you spoke, but the question being about any doubt regarding languages or programming involving them, or conceptual. In case of your doubt for example it is interesting to reduce the code to the minimum necessary to reproduce the problem and cite in text the error message or log that is being presented.

  • It is also interesting to break your other doubts into individual questions concerning each subject. P.S.: Very good your code. Take the opportunity to use the tool and ask questions here.

  • Also ask questions about the operation of the site in the area Meta (meta.pt.stackoverflow.com), which is a Q&A apart. And there is also worth the search.

  • Finally pay attention to the importance of adapting the title of the question to the question being asked, in your case as many were very generic and less useful to locate.

  • Piovezan, I appreciate the tips... It is my first post and I promise to follow your guidelines in the next...

Show 1 more comment

1 answer

2

I made several small modifications to make your code run.

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

#define MAX 100
#define QACOES 5

struct Data 
{
    int dia;
    int mes;
    int ano;
};

struct bvalores
{
    char codigoAcao[6];
    char areaAtuacao[MAX];
    struct Data data;
    float valorAbertura = 0;
    float valorFechamento = 0;
    double variAcao;
};

struct bvalores acoes[QACOES];
int contador;

//recebe os dados digitados pelo usuário
void registros(struct bvalores* acoes)
{
    setlocale(LC_ALL, "Portuguese");

    printf("Digite o código da ação: ");
    scanf("%s", acoes->codigoAcao);
    printf("Digite a área de atuação da empresa: ");
    scanf("%s", acoes->areaAtuacao);
    printf("Qual o valor de aberta: ");
    scanf("%f", &acoes->valorAbertura);
    printf("Qual o valor de fechamento: ");
    scanf("%f", &acoes->valorFechamento);

    acoes->variAcao = (acoes->valorFechamento - acoes->valorAbertura) / acoes->valorAbertura;
    acoes->variAcao *= 100;

    printf("Data de lançamento: ");
    scanf("%d/%d/%d", &acoes->data.dia, &acoes->data.mes, &acoes->data.ano);
}

//registra cada ação com seus respectivos dados em uma posição da memória
void novoregistro()
{
    setlocale(LC_ALL, "Portuguese");

    if (contador < QACOES)
    {
        //*(acoes + contador) = (struct bvalores*)malloc(1 * sizeof(struct bvalores));
        registros(&acoes[contador]);
        contador++;
    }
    else
    {
        printf("Só é possível 5 registros. Limite excedido");
    }
}

char menu()
{
    setlocale(LC_ALL, "Portuguese");

    printf("\n");
    printf("Digite [I] para incluir um novo registro: \n");
    printf("Digite [R] para visualizar a variação das ações registradas: \n");
    printf("Digite [S] para sair do programa: \n");

    printf("\nQual a opção desejada: ");

    int opcao = getchar();
    int c;

    while ((c = getchar()) != '\n' && c != EOF)
    {
        opcao = c;
    }
    return opcao;   
}

//função que monta um relatório dos registro das açoes
void relatorio()
{
    setlocale(LC_ALL, "Portuguese");
    struct bvalores* acao;

    for (int i = 0; i < contador; i++)
    {
        acao = &acoes[i];
        printf("Ação da bolsa: %s  -  Area de atuação: %s\n", acao->codigoAcao, acao->areaAtuacao);
        printf("Data da operação: %02d/%02d/%04d\n", acao->data.dia, acao->data.mes, acao->data.ano);
        printf("\n");
        printf("Valor de abertura: R$ %.2f  -  Valor de fechamento: R$ %.2f\n", acao->valorAbertura, acao->valorFechamento);
        printf("Variãção do dia: %.2f%%", acao->variAcao);
        printf("\n");
    }
}

int main()
{
    char sopcao;

    do 
    {
        sopcao = menu();
        switch (sopcao)
        {
        case 'i':
        case 'I':
            novoregistro();
            break;

        case 'R':
        case 'r':
            relatorio();
            break;

        default:
            printf("Opção invalida");
            break;
        }
    } while (sopcao != 'S' && sopcao != 's');   

    //system("pause");
    return 0;
}

See it working on ideone.com

I tried to tweak your code as little as possible, even when it hurts some good practices (see explanations below):

  1. char codigoAcao[6];

    You need to always leave extra space for the terminator string. e.g., the string "PETR4" is represented by the characters 'P', 'E', 'T', 'R', '4', '\0'.

  2. struct bvalores acoes[QACOES];

    You don’t need a pointer vector for actions. Since the number of actions is fixed, a simple action vector is sufficient.

  3. int contador = 0;

    While I haven’t touched its implementation, as global variables and statistics are initialized "zeroed", it is good practice to always initialize all variables (not to mention initialize local variables).

  4. setlocale(LC_ALL, "Portuguese");

    Locales are a well-advanced subject and do not want to go into detail. That said LC_ALL is a powerful (best avoided) sledgehammer, and Portuguese is not portable. Furthermore, I believe that set the locale only once is enough for your application.

  5.  printf("Digite o código da ação: ");
     scanf("%s", acoes->codigoAcao);
     printf("Digite a área de atuação da empresa: ");
     scanf("%s", acoes->areaAtuacao);
    

    In C vectors decay into pointers, i.e., something like char codigoAcao[6] is seen as a char* pointing to the first element of the vector. Thus, when reading a string no need to use &.

  6.   acoes->variAcao = (acoes->valorFechamento - acoes->valorAbertura) / acoes->valorAbertura;
    

    I had a little error in the account that produced negative variations for actions in high. I had to reverse opening and closing.

  7.  //*(acoes + contador) = (struct bvalores*)malloc(1 * sizeof(struct bvalores));
     registros(&acoes[contador]);
    

    Due to the change in item 2 it is no longer necessary to dynamically allocate memory. In compensation it becomes necessary to pass the address of the action to the function registros.

  8.  for (int i = 0; i < contador; i++)
     {
         acao = &acoes[i];
         printf("Ação da bolsa: %s  -  Area de atuação: %s\n", acao->codigoAcao, acao->areaAtuacao);
         printf("Data da operação: %02d/%02d/%04d\n", acao->data.dia, acao->data.mes, acao->data.ano);
         printf("\n");
         printf("Valor de abertura: R$ %.2f  -  Valor de fechamento: R$ %.2f\n", acao->valorAbertura, acao->valorFechamento);
         printf("Variãção do dia: %.2f%%", acao->variAcao);
         printf("\n");
     }
    

    Here there were several small modifications.

    • I traded <= for < to avoid accessing uninitialized or off-vector actions.
    • The logic to access each action has also been modified according to items 2 and 7.
    • Several small changes in strings formatting.

OBS: I didn’t use printf_s and scanf_s because they are not available on glibc (in fact, I’ve never seen these functions used outside of the Microsoft world). Researching on the subject, it seems to me that there is some controversy regarding TR 24731-1, that being said, if portability is not a priority it is up to you to use the versions safe.

system("pause"); also works only on Windows and does not make much sense for a program that already pauses to read from the keyboard at other points.

  • Thank you very much for the guidelines, I am not from the programming area, but my course has some subjects and really, I did not pay attention to some concepts. The question of dynamic allocation is an item requested at work as required. Even so I will read and study each of your comments and return here with a feedback. Again, thank you so much for the guidance.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.