C语言ROT13加解密项目求助:字符串读取与字符转换问题
C语言ROT13加解密项目问题解决
一、解决fgets读取后输出乱码的问题
你的代码出现乱码有两个核心原因:
scanf("%i", &menu)读取数字后,输入缓冲区里的换行符\n会被后续的fgets直接读取,导致text一开始就拿到空行。- 循环遍历用了
sizeof(text),会把数组中未初始化的随机内存内容也输出,这就是乱码的来源。
修复方法:
- 在
scanf后清理输入缓冲区的残留换行符; - 循环只遍历到字符串结束符
'\0',而非整个数组长度。
二、实现ROT13加解密(无需大量if/switch)
ROT13的核心规则是字母循环移动13位,非字母字符保持不变。使用**查找表(LUT)**是最高效且简洁的实现方式:
- 创建一个256字节的数组
rot13_lut,覆盖所有ASCII字符; - 对小写字母:
a-m映射到n-z,n-z映射到a-m; - 对大写字母:
A-M映射到N-Z,N-Z映射到A-M; - 其他字符直接映射自身。
修改后的完整代码
#include <stdio.h> #include <string.h> // 预定义ROT13查找表 char rot13_lut[256]; // 初始化查找表 void init_rot13_lut() { for (int i = 0; i < 256; i++) { if (i >= 'a' && i <= 'm') { rot13_lut[i] = i + 13; } else if (i >= 'n' && i <= 'z') { rot13_lut[i] = i - 13; } else if (i >= 'A' && i <= 'M') { rot13_lut[i] = i + 13; } else if (i >= 'N' && i <= 'Z') { rot13_lut[i] = i - 13; } else { rot13_lut[i] = i; // 非字母字符保持不变 } } } void Encrypt() { char text[50]; printf("Insert the desired text (Maximum of 50 characters): \n"); // 读取前先确保缓冲区干净,处理残留换行 int c; while ((c = getchar()) != '\n' && c != EOF); fgets(text, sizeof(text), stdin); // 去掉fgets读取的换行符(如果存在) text[strcspn(text, "\n")] = '\0'; printf("Original text: %s\n", text); printf("Encrypted text: "); for (int i = 0; text[i] != '\0'; i++) { printf("%c", rot13_lut[(unsigned char)text[i]]); } printf("\n"); } void Decrypt() { // ROT13加密解密是同一个操作,直接复用逻辑即可 char text[50]; printf("Insert the text to decrypt (Maximum of 50 characters): \n"); int c; while ((c = getchar()) != '\n' && c != EOF); fgets(text, sizeof(text), stdin); text[strcspn(text, "\n")] = '\0'; printf("Encrypted text: %s\n", text); printf("Decrypted text: "); for (int i = 0; text[i] != '\0'; i++) { printf("%c", rot13_lut[(unsigned char)text[i]]); } printf("\n"); } int main() { int menu = 0; // 初始化menu变量,避免未定义行为 init_rot13_lut(); // 初始化查找表 while (menu == 0) { printf("Choose one of the following options: \n"); printf("[1] Encrypt\n"); printf("[2] Decrypt\n"); scanf("%i", &menu); if (menu == 1) { Encrypt(); menu = 0; // 执行完后重置菜单,回到循环 } if (menu == 2) { Decrypt(); menu = 0; } if (menu != 1 && menu != 2) { printf("Invalid option, please try again.\n"); menu = 0; // 清理无效输入后的缓冲区 int c; while ((c = getchar()) != '\n' && c != EOF); } } return 0; }
关键改动说明
- 初始化menu变量:原代码中
menu未初始化就进入循环,属于未定义行为,必须初始化为0; - 输入缓冲区清理:每次
scanf后用循环读掉残留的换行符,避免fgets读取空内容; - 字符串截断:用
strcspn去掉fgets读取的换行符,避免输出多余空行; - ROT13查找表:一次初始化后可重复使用,加解密逻辑完全一致(因为13*2=26,刚好是字母表长度);
- 循环终止条件:遍历到
'\0'为止,只输出有效字符串内容。
内容的提问来源于stack exchange,提问作者white as void
相关产品推荐
相关产品推荐

