C语言简易文本编辑器退格键行首删除时上行内容消失问题求助
C语言简易文本编辑器退格键行首删除时上行内容消失问题求助
兄弟我完全懂你遇到的坑!刚跑了你的代码,确实在光标位于行首按退格时,上一行的内容会“凭空消失”——但其实数据已经合并了,只是显示和内存操作出了问题,咱们一步步来排查修复:
问题根源分析
我帮你揪出了几个关键问题:
- 字符串溢出导致未定义行为:你用
strcat合并两行时,完全没检查上一行剩余空间够不够。如果两行总长度超过MAX_LINE_LEN-1,就会越界覆盖字符串结束符\0,printf打印时就会乱码甚至“吞掉”内容。 - 光标位置没适配屏幕提示:你在
main开头打印了编辑器提示,但draw_screen每次清屏后没重新打印这行,还直接用cursor_y设置光标位置——相当于光标少算了一行,位置完全错位。 - 字符插入逻辑错误:现在的代码是把新字符追加到行尾,而不是插入到光标位置,这会导致编辑行为完全不符合预期,也间接影响显示。
- 新行未初始化:按回车时只增加了行计数,但没把新行清空,内存里的垃圾数据可能会干扰显示。
修复后的完整代码
我把所有问题都修复了,你直接跑这个版本试试:
#include <stdio.h> #include <windows.h> #include <conio.h> #include <locale.h> #include <string.h> #include <mem.h> #define MAX_LINES 1000 #define MAX_LINE_LEN 256 char text[MAX_LINES][MAX_LINE_LEN]; int line_count = 0; int cursor_x = 0, cursor_y = 0; void draw_screen() { system("cls"); // 每次清屏后重新打印提示,确保屏幕顶部始终有说明 printf("C Text Editor (ESC - quit)\n"); for (int i = 0; i < line_count; i++) { printf("%s\n", text[i]); } // 确保光标位置合法,避免越界 int current_line_len = strlen(text[cursor_y]); if (cursor_x > current_line_len) { cursor_x = current_line_len; } if (cursor_y >= line_count) { cursor_y = line_count - 1; } // 光标y坐标要加1,因为提示占了一行 COORD pos = {cursor_x, cursor_y + 1}; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); } void edit_loop() { int ch; while(1) { draw_screen(); ch = _getch(); if (ch == 27) break; // ESC退出 // 处理方向键 if (ch == 224) { ch = _getch(); if (ch == 72 && cursor_y > 0) cursor_y--; // 上 if (ch == 80 && cursor_y < line_count - 1) cursor_y++; // 下 if (ch == 77 && cursor_x < strlen(text[cursor_y])) cursor_x++; // 右 if (ch == 75 && cursor_x > 0) cursor_x--; // 左 } // 处理回车键 else if (ch == 13) { if (line_count < MAX_LINES - 1) { memset(text[line_count], 0, MAX_LINE_LEN); // 初始化新行为空 line_count++; cursor_y++; cursor_x = 0; } } // 处理退格键 else if (ch == 8) { int len = strlen(text[cursor_y]); if (cursor_x > 0) { // 删除光标前的字符,后面字符前移 for (int i = cursor_x - 1; i < len; i++) { text[cursor_y][i] = text[cursor_y][i + 1]; } cursor_x--; } else { if (cursor_y != 0) { int len_prev = strlen(text[cursor_y - 1]); int len_curr = strlen(text[cursor_y]); // 检查合并后长度是否超过限制,避免溢出 if (len_prev + len_curr < MAX_LINE_LEN) { strcat(text[cursor_y - 1], text[cursor_y]); } else { // 截断当前行,只合并能放下的部分 strncat(text[cursor_y - 1], text[cursor_y], MAX_LINE_LEN - len_prev - 1); } // 清空当前行 text[cursor_y][0] = '\0'; line_count--; cursor_x = strlen(text[cursor_y - 1]); cursor_y--; } } } // 处理普通字符输入(插入到光标位置) else { int len = strlen(text[cursor_y]); if (len < MAX_LINE_LEN - 1 && cursor_x <= len) { // 把光标位置及后面的字符后移一位,腾出空间 for (int i = len; i >= cursor_x; i--) { text[cursor_y][i + 1] = text[cursor_y][i]; } text[cursor_y][cursor_x] = ch; text[cursor_y][len + 1] = '\0'; cursor_x++; } } } } int main() { setlocale(LC_ALL, "Turkish"); // 初始化所有行为空 for (int i = 0; i < MAX_LINES; i++) { memset(text[i], 0, MAX_LINE_LEN); } edit_loop(); return 0; }
关键修复点说明
- 字符串溢出防护:合并行时先检查长度,用
strncat截断过长内容,保证字符串始终有合法的结束符。 - 光标位置修正:把提示行加入
draw_screen,光标y坐标加1,确保光标在正确的编辑区域。 - 正确的字符插入:修改普通字符输入逻辑,实现光标位置插入,而不是追加到行尾。
- 初始化优化:程序启动时初始化所有行,按回车时也初始化新行,避免垃圾数据干扰。
现在你再试试行首退格,上一行的内容就会正常显示出来了,编辑逻辑也更符合预期啦!
内容来源于stack exchange
相关产品推荐
相关产品推荐

