You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何根据scanf获取的用户输入访问结构体不同成员?

解决C语言中根据字符串输入访问结构体成员的问题

在C语言中,由于没有反射机制,无法直接通过字符串名称访问结构体成员,但可以通过分支判断或者查找表+指针运算两种方式实现需求。以下是具体实现方案:


方案一:分支判断(简单直接,适合少量成员)

如果结构体成员数量不多,直接通过strcmp判断输入字符串,针对每个成员编写对应的逻辑即可。这种方式代码直观,易于理解。

完整代码示例

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

struct class {
    char name[50];
    int score;
    char grade[2];
} data[100];
int data_count = 0; // 记录已填充的学生数量

// 统计指定成员的唯一值数量
int count_unique(struct class* data, int count, const char* member_name) {
    if (strcmp(member_name, "name") == 0) {
        int unique = 0;
        for (int i = 0; i < count; i++) {
            int exists = 0;
            // 检查当前name是否已出现过
            for (int j = 0; j < i; j++) {
                if (strcmp(data[i].name, data[j].name) == 0) {
                    exists = 1;
                    break;
                }
            }
            if (!exists) unique++;
        }
        return unique;
    } 
    else if (strcmp(member_name, "score") == 0) {
        int unique = 0;
        for (int i = 0; i < count; i++) {
            int exists = 0;
            for (int j = 0; j < i; j++) {
                if (data[i].score == data[j].score) {
                    exists = 1;
                    break;
                }
            }
            if (!exists) unique++;
        }
        return unique;
    } 
    else if (strcmp(member_name, "grade") == 0) {
        int unique = 0;
        for (int i = 0; i < count; i++) {
            int exists = 0;
            for (int j = 0; j < i; j++) {
                if (strcmp(data[i].grade, data[j].grade) == 0) {
                    exists = 1;
                    break;
                }
            }
            if (!exists) unique++;
        }
        return unique;
    } 
    else {
        printf("无效的成员名称:%s\n", member_name);
        return -1;
    }
}

int main() {
    // 示例数据填充
    strcpy(data[0].name, "Alice"); data[0].score = 90; strcpy(data[0].grade, "A");
    strcpy(data[1].name, "Bob"); data[1].score = 85; strcpy(data[1].grade, "B");
    strcpy(data[2].name, "Alice"); data[2].score = 90; strcpy(data[2].grade, "A");
    data_count = 3;

    char input[10];
    printf("请输入要统计的成员名称(name/score/grade):");
    scanf("%s", input);
    getchar(); // 消耗输入后的换行符

    int result = count_unique(data, data_count, input);
    if (result != -1) {
        printf("唯一的%s数量:%d\n", input, result);
    }

    return 0;
}

方案二:查找表+指针运算(可扩展,避免代码重复)

如果结构体成员较多,使用查找表映射字符串到成员的偏移量和比较函数,通过指针运算动态访问成员,避免重复代码。核心用到offsetof宏获取成员在结构体中的字节偏移。

完整代码示例

#include <stdio.h>
#include <string.h>
#include <stddef.h> // 用于offsetof宏
#include <stdlib.h> // 用于malloc和qsort

struct class {
    char name[50];
    int score;
    char grade[2];
} data[100];
int data_count = 0;

// 成员比较函数
int compare_names(const void* a, const void* b) {
    return strcmp(*(const char**)a, *(const char**)b);
}

int compare_scores(const void* a, const void* b) {
    return *(const int*)a - *(const int*)b;
}

int compare_grades(const void* a, const void* b) {
    return strcmp(*(const char**)a, *(const char**)b);
}

// 成员信息结构体:映射名称、偏移量、比较函数、元素大小
typedef struct {
    const char* name;
    size_t offset;
    int (*comparator)(const void*, const void*);
    size_t elem_size;
} MemberInfo;

MemberInfo member_map[] = {
    {"name", offsetof(struct class, name), compare_names, sizeof(char*)},
    {"score", offsetof(struct class, score), compare_scores, sizeof(int)},
    {"grade", offsetof(struct class, grade), compare_grades, sizeof(char*)},
    {NULL, 0, NULL, 0} // 哨兵元素,用于遍历结束判断
};

// 通用统计唯一值函数
int count_unique(struct class* data, int count, const char* member_name) {
    // 查找对应的成员信息
    MemberInfo* info = NULL;
    for (int i = 0; member_map[i].name != NULL; i++) {
        if (strcmp(member_map[i].name, member_name) == 0) {
            info = &member_map[i];
            break;
        }
    }
    if (!info) {
        printf("无效的成员名称:%s\n", member_name);
        return -1;
    }

    // 分配内存存储成员指针/值
    void* elements = malloc(count * info->elem_size);
    if (!elements) {
        perror("内存分配失败");
        return -1;
    }

    // 填充成员数据
    for (int i = 0; i < count; i++) {
        void* member_addr = (char*)&data[i] + info->offset;
        if (info->elem_size == sizeof(char*)) {
            // 对于字符数组成员,存储其指针
            *(char**)((char*)elements + i * sizeof(char*)) = member_addr;
        } else if (info->elem_size == sizeof(int)) {
            // 对于整数成员,存储其值
            *(int*)((char*)elements + i * sizeof(int)) = *(int*)member_addr;
        }
    }

    // 排序以便统计唯一值
    qsort(elements, count, info->elem_size, info->comparator);

    // 统计唯一值数量
    int unique_count = 0;
    if (count > 0) {
        unique_count = 1;
        for (int i = 1; i < count; i++) {
            void* curr = (char*)elements + i * info->elem_size;
            void* prev = (char*)elements + (i-1)*info->elem_size;
            if (info->comparator(curr, prev) != 0) {
                unique_count++;
            }
        }
    }

    free(elements);
    return unique_count;
}

int main() {
    // 示例数据填充
    strcpy(data[0].name, "Alice"); data[0].score = 90; strcpy(data[0].grade, "A");
    strcpy(data[1].name, "Bob"); data[1].score = 85; strcpy(data[1].grade, "B");
    strcpy(data[2].name, "Alice"); data[2].score = 90; strcpy(data[2].grade, "A");
    data_count = 3;

    char input[10];
    printf("请输入要统计的成员名称(name/score/grade):");
    scanf("%s", input);
    getchar();

    int result = count_unique(data, data_count, input);
    if (result != -1) {
        printf("唯一的%s数量:%d\n", input, result);
    }

    return 0;
}

两种方案对比

  • 分支判断:代码简单直接,适合成员数量少的场景,但存在重复代码,新增成员时需要修改函数逻辑。
  • 查找表+指针运算:代码更通用,新增成员只需在查找表中添加条目,无需修改统计逻辑,但对指针和内存管理要求稍高。

内容的提问来源于stack exchange,提问作者dru

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 07:55:18