【问题标题】:Printf, scanf & For Loop problemsPrintf、scanf 和 For 循环问题
【发布时间】:2015-01-30 00:15:33
【问题描述】:

我的目标是能够将成员输入到学生数据库的数组的每个结构中。我知道我的 for 循环在某种程度上是错误的,但我不知道如何修复它...输出采用名字,然后在不输入输入的情况下打印循环的其余部分。

显然问题在于我对 printf 和 scanf 的功能缺乏了解。但只是从我无知的角度来看,我不明白为什么它不起作用。

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

typedef struct {
    char *name;
    char *surname;
    char *UUN;
    char *department;
    char gender;
    int age;
} student_t;

student_t findOldest(student_t *studentarr, int len) {
    int i;
    student_t max=*(studentarr+0);

    for (i=1; i < len; i++) {
        if((*(studentarr+i)).age > max.age)
            max = *(studentarr+i);
    }

    return max;
}

int main() {
    int i;
    student_t result;
    student_t stdt[6]={{"John","Bishop","s1234","Inf",'m',18},{"Lady","Cook","s2345","Eng",'f',21},{"James","Jackson","s33456","Eng",'m',17}};
    student_t *p=&stdt[0];

    for(i=3;i<6;i++){ /* This is where I'm stuck */
        printf("\nFirst Name: ");
        scanf("%s",stdt[i].name);
        printf("\nSurname: ");
        scanf("%s",stdt[i].surname);
        printf("\nUUN: ");
        scanf("%s",stdt[i].UUN);
        printf("\nDepartment: ");
        scanf("%s",stdt[i].department);
        printf("\nGender (m/f): ");
        scanf(" %c",&stdt[i].gender);
        printf("\nAge: ");
        scanf("%d",&stdt[i].age);
    }

    findOldest(p,6);
    result = findOldest(p,6);
    printf("\nThe student of oldest age:%s, %s, %s, %s, %c, %d\n",result.name,result.surname,result.UUN,result.department,result.gender,result.age);

    return 0;
}

【问题讨论】:

  • 如果您将 struct char* 成员声明为 char xyz[200](任意长度),它将起作用
  • 您也没有在(大部分)scanf() 调用之间跳过空格(包括换行符)...

标签: c for-loop struct printf scanf


【解决方案1】:

您正在尝试将数据写入未分配的空间。更改您的结构以使用 char[]:

typedef struct {
    char name[200];
    char surname[200];
    char UUN[200];
    char department[200];
    char gender;
    int age;
} student_t;

(这里的 200 只是一个示例;根据您的需要进行调整)

如果您真的想将它们保留为char*,您可以:

i) 使用malloc 预先分配每个:

    ...
    printf("\nFirst Name: ");
    stdt[i].name = malloc(200);
    scanf("%s",stdt[i].name);
    ...

ii) scanf 到一个缓冲区,然后将结果复制到最终成员:

int main() {
    ...
    char buffer[200];

    for(i=3;i<6;i++){ /* This is where I'm stuck */
        printf("\nFirst Name: ");
        scanf("%s",buffer);
        stdt[i].name = strdup(buffer);
    ...

【讨论】:

  • 我同意了。但是要养成使用安全功能的习惯。使用 sscanf 而不是 scanf。大小是在参数中采用的,这样可以避免缓冲区溢出和讨厌的错误。
  • @Manticore 你就在这里;我只是尝试做最少的更改,以便 OP 可以尝试了解真正使它起作用的原因(从 scanfsscanf 的更改可能会混淆而不是澄清)。
  • sscanf() 从内存中的缓冲区获取其输入。也许您的意思是 fscanf() 具有相同的大小调整功能并从文件流中获取其输入,例如 stdin
  • 使用 malloc() 无法预初始化学生信息表中的前三个条目。
【解决方案2】:
this compiles with no errors/warnings
it implements the desired algorithm
it greatly reduces the complexity of certain parts of the code
it give names to the magic numbers in the code
it eliminates the probability of seg fault events 
   from trying to write to pointers that points nowhere

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

#define MAX_NAME_LEN (20)
#define MAX_SURNAME_LEN (20)
#define MAX_UUN_LEN (20)
#define MAX_DEPARTMENT_LEN (20)

struct student_t
{
    char name[MAX_NAME_LEN];
    char surname[MAX_SURNAME_LEN];
    char UUN[MAX_UUN_LEN];
    char department[MAX_DEPARTMENT_LEN];
    char gender;
    int  age;
};

int findOldest(struct student_t *, int);

#define MAX_STUDENTS (6)

int main()
{
    int i; // loop counter
    int result; // returned index from findOldest()
    struct student_t stdt[MAX_STUDENTS]=
    {
        {"John","Bishop","s1234","Inf",'m',18},
        {"Lady","Cook","s2345","Eng",'f',21},
        {"James","Jackson","s33456","Eng",'m',17}
    };


    // enter info for last 3 students
    for( i=3; i<6; i++ )
    {
        printf("\nEnter First Name: ");
        if( 1 != scanf(" %s", stdt[i].name) )
        { // then, scanf failed
            perror( "scanf failed for name" );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf for name successful

        printf("\nEnter Surname: ");
        if( 1 != scanf(" %s", stdt[i].surname) )
        { // then scanf failed
            perror( "scanf failed for surname" );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf for surname successful

        printf("\nEnter UUN: ");
        if( 1 != scanf(" %s", stdt[i].UUN) )
        { // then scanf failed
            perror( "scanf failed for UUN" );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf for UUN successful

        printf("\nEnter Department: ");
        if( 1 != scanf(" %s",stdt[i].department) )
        { // then scanf failed
            perror( "scanf failed for department" );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf for department successful

        printf("\nEnter Gender (m/f): ");
        if( 1 != scanf(" %c", &stdt[i].gender) )
        { // then scanf failed
            perror( "scanf failed for gender" );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf for gender successful

        printf("\nEnter Age: ");
        if( 1 != scanf(" %d", &stdt[i].age) )
        { // then scanf failed
            perror( "scanf failed for age" );
            exit( EXIT_FAILURE );
        }

        // implied else, scanf for age successful

    } // end for


    result = findOldest( stdt, MAX_STUDENTS );
    printf("\nThe student of oldest age:%s, %s, %s, %s, %c, %d\n",
        stdt[result].name,
        stdt[result].surname,
        stdt[result].UUN,
        stdt[result].department,
        stdt[result].gender,
        stdt[result].age);

    return 0;
} // end function: main

// note: if more than one student has same (oldest) age
//       then the student index of the first student
//       of that age will be returned
int findOldest(struct student_t *studentarr, int len)
{
    int i; // loop index
    int max   = -1;
    int index = -1;

    for (i=0; i < len; i++)
    {
        if( studentarr[i].age > max )
        {
            max = studentarr[i].age;
            index = i;
        } // end if
    } // end for

    return index;
} // end function findOldest

【讨论】:

  • 如果我使用 fscanf 而不是 scanf 可能会更好,以避免在数据输入期间出现任何缓冲区溢出
猜你喜欢
  • 2023-03-08
  • 2017-07-06
  • 1970-01-01
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多