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

C++使用strcpy和strcmp从文件读数据排序数组时大小写分离问题

解决C++排序时姓氏大小写导致的分组问题

这个问题我太熟了——strcmp是严格按照ASCII码值来比较的,而大写字母的ASCII码(65-90)全部小于小写字母(97-122),所以它会把所有首字母大写的姓氏一股脑排在小写开头的前面,完全不管实际的字典顺序。要解决这个问题,核心就是让排序时忽略大小写差异。

下面给你两种实用的解决方案,你可以根据自己的代码风格选:

1. 自定义不区分大小写的字符串比较函数

如果你想继续用C风格的char数组,自己实现一个忽略大小写的strcmp变体是最直接的:

#include <cctype>

// 忽略大小写的字符串比较函数
int strcmpIgnoreCase(const char* str1, const char* str2) {
    while (*str1 != '\0' && *str2 != '\0') {
        // 转成unsigned char避免有符号char的未定义行为
        unsigned char c1 = static_cast<unsigned char>(*str1);
        unsigned char c2 = static_cast<unsigned char>(*str2);
        
        char lowerC1 = tolower(c1);
        char lowerC2 = tolower(c2);
        
        if (lowerC1 != lowerC2) {
            return lowerC1 - lowerC2;
        }
        
        str1++;
        str2++;
    }
    
    // 处理其中一个字符串先结束的情况(比如"Smith"和"Smithson")
    unsigned char c1 = static_cast<unsigned char>(*str1);
    unsigned char c2 = static_cast<unsigned char>(*str2);
    return tolower(c1) - tolower(c2);
}

然后把你排序逻辑里的strcmp替换成这个函数就行。比如假设你用冒泡排序:

struct Customer {
    char lastName[50];
    char firstName[50];
    int daysOfRental;
    double balanceDue;
};

void sortCustomers(Customer customers[], int total) {
    for (int i = 0; i < total - 1; i++) {
        for (int j = 0; j < total - i - 1; j++) {
            // 替换成自定义的忽略大小写比较
            if (strcmpIgnoreCase(customers[j].lastName, customers[j+1].lastName) > 0) {
                // 直接交换整个结构体,比逐个strcpy更高效
                Customer temp = customers[j];
                customers[j] = customers[j+1];
                customers[j+1] = temp;
            }
        }
    }
}

2. 用C++标准库的字符串和排序工具(更现代的写法)

如果可以改用std::string来存储姓名,代码会更简洁易读,还能利用C++标准库的强大功能:

#include <algorithm>
#include <cctype>
#include <string>
#include <vector>

struct Customer {
    std::string lastName;
    std::string firstName;
    int daysOfRental;
    double balanceDue;
};

// 自定义比较器:忽略大小写比较姓氏
bool compareByLastNameIgnoreCase(const Customer& a, const Customer& b) {
    std::string aLower = a.lastName;
    std::string bLower = b.lastName;
    
    // 把两个姓氏都转成小写
    std::transform(aLower.begin(), aLower.end(), aLower.begin(),
                   [](unsigned char c) { return tolower(c); });
    std::transform(bLower.begin(), bLower.end(), bLower.begin(),
                   [](unsigned char c) { return tolower(c); });
    
    return aLower < bLower;
}

// 排序时直接用std::sort
void sortCustomers(std::vector<Customer>& customers) {
    std::sort(customers.begin(), customers.end(), compareByLastNameIgnoreCase);
}

这样处理后,你的示例里的anilo会和Anderson按实际字典序排在一起,smitty会紧跟在Smith后面,xu也不会跑到最后去了。

小提醒

不管用哪种方法,都要注意tolower的参数——一定要转成unsigned char,因为如果你的char是有符号类型,某些扩展ASCII字符(比如0x80以上)会被当成负数,传入tolower会导致未定义行为。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:24:05