Menu
CoddyTech

显示联系人的函数

本课属于 Coddy C 学习旅程的“逻辑与流程”单元。第 53 课,共 63 课。

challenge icon

挑战

简单

在前几课的联系人管理系统基础上,创建一个函数,以格式化的方式显示联系人信息。本课会介绍你需要用到的三个新字符串函数:fgets()、strcspn() 和 strchr()。下文会先逐一说明这些函数,再列出具体要求。

本课使用的新函数:

  • fgets(buffer, size, stdin):读取一行输入,包括其中的空格(与遇到空白字符就停止读取的 scanf 不同)。它会将输入存入 buffer,最多读取 size - 1 个字符。它还会在末尾存入换行符 '\n'。
  • strcspn(str, "\n"):返回 str 中第一个 '\n' 的索引。它可用于移除 fgets 留下的末尾换行符:str[strcspn(str, "\n")] = '\0';
  • strchr(str, ch):在 str 中查找字符 ch,并返回指向该字符位置的指针;如果找不到,则返回 NULL。

你的程序应该:

  1. 使用前几课中的相同 Contact 结构体定义,包含以下成员:
    • 大小为 50 的字符数组 name
    • 大小为 20 的字符数组 phone
    • 大小为 40 的字符数组 email
    • 整数 age
  2. 使用前几课中的相同 createContact 函数,该函数:
    • 为 Contact 结构体动态分配内存
    • 将所有成员初始化为默认值
    • 返回指向联系人的指针
  3. 编写一个 populateContact 函数,该函数:
    • 接收指向 Contact 结构体的指针作为参数
    • 使用 fgets() 读取每个字符串字段(姓名、电话、电子邮件),以便接受包含空格的姓名
    • 读取每个字符串字段后,使用 strcspn() 移除末尾的换行符
    • 使用 scanf("%d", ...) 读取整数年龄字段
    • 读取每个字段之前,按原样打印对应提示,提示后不换行:Enter name: 、Enter phone: 、Enter email: 、Enter age: (这样 === CONTACT DETAILS === 就会紧接在同一行的 Enter age: 后面)
    • 注意:此版本的 populateContact 不会验证电话号码长度:不要添加这项验证,因为测试输入使用的是 555-1234 这样较短的电话号码。
  4. 编写一个名为 displayContact 的函数,该函数:
    • 接收指向 Contact 结构体的常量指针作为参数:const struct Contact *contactPtr
    • 不返回任何内容(void)
    • 严格按照以下格式打印联系人信息:
      • === CONTACT DETAILS ===
      • Name: [name]
      • Phone: [phone]
      • Email: [email]
      • Age: [age] years old
      • ========================
    • 显示基本信息后,计算并显示其他详细信息:
      • 使用 strlen() 计算姓名长度,并打印:Name length: [length] characters
      • 根据年龄确定所属世代类别,并打印:
        • 如果年龄在 0 到 12 之间:Generation: Child
        • 如果年龄在 13 到 19 之间:Generation: Teenager
        • 如果年龄在 20 到 39 之间:Generation: Young Adult
        • 如果年龄在 40 到 59 之间:Generation: Middle-aged Adult
        • 如果年龄为 60 或以上:Generation: Senior
      • 使用 strchr() 检查电子邮件中是否包含字符 '@',并打印:
        • 如果找到 '@':Email format: Valid
        • 如果没有找到 '@':Email format: Invalid
  5. 在 main 函数中:
    • 使用 createContact 函数创建联系人
    • 检查联系人是否创建成功
    • 调用 populateContact 函数填充联系人数据
    • 调用 displayContact 函数,以格式化的方式显示联系人信息
    • 释放动态分配的内存
    • 打印 Program completed successfully

本挑战演示了如何创建一个接收指向结构体的常量指针的显示函数,从而确保该函数不能修改原始数据。你将练习使用 fgets() 读取包含空格的字符串,使用 strcspn() 移除末尾的换行符,通过箭头运算符访问指针指向的结构体成员,使用 strchr() 搜索字符,以及使用条件逻辑对数据进行分类。在参数声明中使用 const 是一种良好做法,可以防止显示函数意外修改联系人数据。

亲手试试

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

typedef struct {
    char name[50];
    char phone[20];
    char email[40];
    int age;
} Contact;

Contact* createContact() {
    Contact* contact = (Contact*)malloc(sizeof(Contact));
    if (contact == NULL) {
        return NULL;
    }
    
    strcpy(contact->name, "");
    strcpy(contact->phone, "");
    strcpy(contact->email, "");
    contact->age = 0;
    
    return contact;
}

void populateContact(Contact* contactPtr) {
    printf("Enter name: ");
    scanf("%s", contactPtr->name);
    
    printf("Enter phone: ");
    scanf("%s", contactPtr->phone);
    
    printf("Enter email: ");
    scanf("%s", contactPtr->email);
    
    printf("Enter age: ");
    scanf("%d", &contactPtr->age);
    
    if (contactPtr->age < 0 || contactPtr->age > 120) {
        printf("Invalid age entered\n");
    } else if (strlen(contactPtr->phone) < 10) {
        printf("Invalid phone number\n");
    } else {
        printf("Contact populated successfully\n");
    }
}

int main() {
    Contact* contact = createContact();
    
    if (contact == NULL) {
        return 1;
    }
    
    populateContact(contact);
    
    printf("Contact Information:\n");
    printf("Name: %s\n", contact->name);
    printf("Phone: %s\n", contact->phone);
    printf("Email: %s\n", contact->email);
    printf("Age: %d\n", contact->age);
    
    free(contact);
    printf("Contact deleted successfully\n");
    
    return 0;
}

逻辑与流程中的所有课

自己练习: C 在线编译器