为什么我不能使用 "fgets" 将字符串读入我的结构元素?

Why I cannot use "fgets" to read a string to an element of my Struct?

我正在尝试使用结构创建一个几乎类似于 "bank" 的程序,但是当程序应该读取字符串时(变量 "nome",即葡萄牙语名称)它完全忽略了我使用的 "fgets"。这是我正在谈论的部分:

printf("\nNome: \n");
fgets(vet[cont+1].nome, sizeof(vet[cont+1].nome), stdin);

而且我很确定问题可能出在我的对象数组的动态分配上。请帮我解决这个问题,谢谢!

PS:对不起,代码是葡萄牙语(我的母语)。

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

/*
Programa realiza uma alocacao dinamica por meio 
de uma funcao que recebe a dimensao e retorna o vetor(ponteiro)
*/

struct CLIENTES
{
    int ano_nasc, cpf[11];
    float renda_m;
    char nome[50];
}; //Lista de Objetos

int main(void) 
{
    //Declaracao de Variaveis
    int cont=0, num, num_2, client, i, j;
    CLIENTES *vet;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    scanf("%d", &num);
    vet = (CLIENTES*)malloc(num*sizeof(int));
    printf("Digite os Dados do Cliente.");

    while (cont != num)
    {  
        printf("\nNome: \n");
        fgets(vet[cont+1].nome, sizeof(vet[cont+1].nome), stdin);
        printf("\nAno de Nascimento: ");
        scanf("%d", &vet[cont+1].ano_nasc);
        printf("\nCPF: ");
        scanf("%d", &vet[cont+1].cpf);
        printf("\nRenda Mensal: ");
        scanf("%d", &vet[cont+1].renda_m);
        cont++;
    }

    printf("\nDigite o numero do cliente que voce deseja conferir: ");
    scanf("%d", &num_2);
    for (i=0;i<num;i++)
    {
        if(num_2 == num)
        {
            printf("\nO que deseja saber sobre ele?\n");
            printf("1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n\n\n");
            scanf("%d", &client);
            if (client == 1)
            {
                printf("Nome: %c", vet[num_2].nome );
            }
            else if(client == 2)
            {
                printf("Ano de Nascimento: %d", vet[num_2].ano_nasc );
            }
            else if(client == 3)
            {
                for(j=0;j<11;j++)
                {
                    printf("CPF: %d", vet[num_2].cpf[j]);
                }
            }
            else if(client == 4)
            {
                printf("Renda Mensal: %f", vet[num_2].renda_m );
            } 
        }
    }

    //Finalizando o Programa
    printf("\n\nFim do Programa!");
    getch();
    return 0;
}

我看到的问题:

  1. 您在行中分配了错误的内存量:

    vet = (CLIENTES*)malloc(num*sizeof(int));
    

    应该是:

    vet = malloc(num*sizeof(*vet));
    

    参见 Do I cast the result of malloc?。答案解释了为什么你不应该转换 malloc 的 return 值。

  2. 您在 scanf 之后使用 fgetsscanf 将换行符和其他空白字符留在流中。之后立即调用 fgets 时,fgets 只读取空格和换行符。您需要添加代码以在调用 scanf 之后和调用 fgets.

    之前忽略该行的其余部分
    // Skip everything up to and including the newline.
    int c;
    while ( (c = getc(stdin)) != EOF && c != '\n');
    

    之后,

    fgets(vet[cont+1].nome, sizeof(vet[cont+1].nome), stdin);
    

    应该能正确读取数据。

  3. 您在行中使用了错误的值:

    scanf("%d", &vet[cont+1].cpf);
    

    cpfint 上的数组。如果你只想读一个int,你可以使用:

    scanf("%d", &vet[cont+1].cpf[0]);
    
  4. 您在行中使用了错误的格式说明符:

    scanf("%d", &vet[cont+1].renda_m);
    

    应该是:

    scanf("%f", &vet[cont+1].renda_m);
        // ^^ %f not %d
    
  5. 您使用错误的索引访问数组 vet。凡是用vet[cont+1]的地方,都应该是vet[cont]。通过使用 vet[cont+1],您没有使用数组的第一个元素 vet[0],并且通过访问 vet[num].

    [=68 访问超出分配的内存=]

如果您解决了上述问题,您的程序可能会运行。

以下代码:

1) 更正了我在评论中列出的所有问题。

2) 删除了 OP 发布代码的一些功能,

请注意使用 while(getchar() ... 循环来清除任何剩余白色的标准输入 space。

3) 如果用户尝试在 nome 字段中输入任何白色 space

,仍然会失败

4) 代码总是检查错误

5) 代码总是清理(在退出

之前使用 'free( vet );'

编译时,始终启用所有警告, (对于 gcc,至少使用“-Wall -Wextra -pedantic”)

#include <stdio.h>
//#include <conio.h> // not portable, do not use
#include <stdlib.h>

/*
Programa realiza uma alocacao dinamica por meio
de uma funcao que recebe a dimensao e retorna o vetor(ponteiro)
*/

#define NUM_CPF      (11)
#define MAX_NOME_LEN (50)

struct CLIENTES
{
    int ano_nasc;
    int cpf[NUM_CPF];
    float renda_m;
    char nome[ MAX_NOME_LEN ];
}; //Lista de Objetos


int main(void)
{
    //Declaracao de Variaveis
    int cont=0;
    int num;
    int client;
    int i;
    int j;
    struct CLIENTES *vet = NULL;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    if( 1 != scanf("%d", &num) )
    { // scanf failed
        perror( "scanf for num failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, scanf successful

    // clear stdin
    while( getchar() != '\n' );

    if( NULL == (vet = malloc(num*sizeof(struct CLIENTES)) ) )
    { // then malloc failed
        perror( "malloc for multiple struct CLIENTES failed" );
        exit( EXIT_FAILURE );
    }

    // implied else, malloc successful

    while (cont != num)
    {
        printf("\nNome: ");
        fflush(stdout);
        if( NULL == fgets(vet[cont].nome, MAX_NOME_LEN, stdin) )
        { // fgets failed
            perror( "fgets failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, fgets successful

       // clear stdin
       //while( getchar() != '\n' );

        printf("\nAno de Nascimento: ");
        if( 1 != scanf("%d", &vet[cont].ano_nasc) )
        { // scanf failed
            perror( "scanf for ano_nasc failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        printf("\nCPF: ");
        if( 1 != scanf("%d", vet[cont].cpf) )
        { // scanf failed
            perror( "scanf for cpf failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        printf("\nRenda Mensal: ");
        if( 1 != scanf("%f", &vet[cont].renda_m) )
        { // scanf failed
            perror( "scanf for renda_m failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        // clear stdin
        while( getchar() != '\n' );

        cont++;
    } // end while



    for (i=0;i<num;i++)
    {
        printf("\nO que deseja saber sobre ele?\n");
        printf("1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n\n\n");
        if( 1 != scanf("%d", &client) )
        { // scanf failed
            perror( "scanf for client failed" );
            free( vet );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf successful

        switch( client )
        {
        case 1:
            printf("Nome: %49s", vet[i].nome );
            break;

        case 2:

            printf("Ano de Nascimento: %d", vet[i].ano_nasc );
            break;

        case 3:
            for(j=0; j< NUM_CPF; j++)
            {
                printf("CPF[%d] =  %d", j, vet[i].cpf[j]);
            }
            printf( "\n" );
            break;

        case 4:
            printf("Renda Mensal: %f", vet[i].renda_m );
            break;

        default:
            printf("ERROR: invalid client value, range 1...4\n");
            break;
        }; // end switch
    } // end for

    //Finalizando o Programa
    printf("\n\nFim do Programa!");
    free( vet );
    system( "pause" );
    return 0;
} // end function: main

另一个版本,有循环和功能。

#include <stdio.h>
//#include <conio.h> // not portable, do not use
#include <stdlib.h>

/*
Programa realiza uma alocacao dinamica por meio
de uma funcao que recebe a dimensao e retorna o vetor(ponteiro)
*/

#define NUM_CPF      (11)
#define MAX_NOME_LEN (50)

struct CLIENTES
{
    int ano_nasc;
    int cpf[NUM_CPF];
    float renda_m;
    char nome[ MAX_NOME_LEN ];
}; //Lista de Objetos

void soErros(char erro[20]){

    perror(erro);
    exit( EXIT_FAILURE );

}

int main(void)
{
    //Declaracao de Variaveis
    int cont=0;
    int num;
    int client, saida;
    int i;
    int j;
    int k;
    struct CLIENTES *vet = NULL;

    //Leitura de Dados
    printf("Digite o numero de Clientes: ");
    if( 1 != scanf("%d", &num) )
    { // scanf failed
        soErros("scanf for num failed" );
    }

    // implied else, scanf successful

    // clear stdin
    while( getchar() != '\n' );

    if( NULL == (vet = malloc(num*sizeof(struct CLIENTES)) ) )
    { // then malloc failed
        soErros("malloc for multiple struct CLIENTES failed");
    }

    // implied else, malloc successful

    while (cont != num)
    {
        printf("\nNome: ");
        fflush(stdout);
        if( NULL == fgets(vet[cont].nome, MAX_NOME_LEN, stdin) )
        { // fgets failed
            soErros("fgets failed");
        }

        // implied else, fgets successful

       // clear stdin
       //while( getchar() != '\n' );

        printf("\nAno de Nascimento: ");
        if( 1 != scanf("%d", &vet[cont].ano_nasc) )
        { // scanf failed
            soErros("scanf for ano_nasc failed");
        }

        // implied else, scanf successful

        printf("\nCPF: ");
        if( 1 != scanf("%d", vet[cont].cpf) )
        { // scanf failed
            soErros("scanf for cpf failed");
        }

        // implied else, scanf successful

        printf("\nRenda Mensal: ");
        if( 1 != scanf("%f", &vet[cont].renda_m) )
        { // scanf failed
            soErros("scanf for renda_m failed");
        }

        // implied else, scanf successful

        // clear stdin
        while( getchar() != '\n' );

        cont++;
    } // end while
    int escolha = 0;
    do{

        int *esc = &escolha;
        printf("\nDeseja saber sobre qual cliente?: ");

        for (i=0;i<num;i++)
        {
            printf("\n%d --- %s",i , vet[i].nome);
        } // end for

        if( 1 != scanf("%d", &esc) )
        { // scanf failed
            soErros("scanf for ano_nasc failed");
        } // end if

        printf("\nVocê escolheu o cliente %s", vet[escolha].nome);

        for(i=0;i<num;i++)
        {
            if(i == escolha){
                printf("\n0-Sair\n1-Nome\n2-Ano de Nascimento\n3-CPF\n4-Renda Mensal\n");
                if( 1 != scanf("%d", &client) )
                { // scanf failed
                    soErros("scanf for client failed");
                }

                // implied else, scanf successful

                switch( client )
                {
                case 0:
                    printf("Saindo do menu");
                    break;
                case 1:
                    printf("Nome: %49s", vet[i].nome );
                    break;

                case 2:

                    printf("Ano de Nascimento: %d", vet[i].ano_nasc );
                    break;

                case 3:
                    printf("CPF = ");
                    for(j=0; j< NUM_CPF; j++)
                    {
                        printf("%d", vet[i].cpf[j]);
                    }
                    printf( "\n" );
                    break;

                case 4:
                    printf("Renda Mensal: %f", vet[i].renda_m );
                    break;

                default:
                    printf("ERROR: invalid client value, range 1...4\n");
                    system("cls || clear");
                    break;
                }; // end switch
                printf( "\n" );
            } // end if
        } //end for
        printf("Continuar[1]\nSair[0]\n: ");
        if( 1 != scanf("%d", &saida) )
        {
            soErros("Erro de continuidade");
        } // end if

        switch( saida )
        {
        case 0:
            break;
        }
    } // end do
    while (saida);

    //Finalizando o Programa
    printf("\nFim do Programa!\n");
    free( vet );
    system( "pause" );
    return 0;
} // end function: main