哈工大C语言编程练习28是计算机专业学生接触指针与内存管理的重要转折点。这个练习通常安排在C语言课程的中后期,此时学生已经掌握了基础语法、流程控制和函数使用,需要通过实际编程任务来理解计算机底层的内存运作机制。
我在大二时第一次完成这个练习,当时花了整整三天才调试通过。现在回头看,这个练习设计得非常精妙——它用看似简单的字符串操作,迫使你直面指针、内存分配和越界访问这些C语言中最核心也最容易出错的概念。
典型的练习28题目会给出如下要求:
"编写程序实现字符串的逆序存储,要求:
这个题目实际上在考察四个核心能力:
c复制#include <stdio.h>
#include <stdlib.h>
void reverse_string(char *str) {
if (str == NULL) return;
char *end = str;
while (*end) end++; // 找到字符串结尾
end--; // 回退到最后一个非空字符
while (str < end) {
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}
int main() {
char input[1024];
printf("输入字符串: ");
fgets(input, sizeof(input), stdin);
// 分配动态内存
char *dynamic_str = (char*)malloc(strlen(input) + 1);
if (dynamic_str == NULL) {
fprintf(stderr, "内存分配失败\n");
return 1;
}
strcpy(dynamic_str, input);
reverse_string(dynamic_str);
printf("逆序结果: %s\n", dynamic_str);
free(dynamic_str);
return 0;
}
c复制#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* reverse_string_advanced(const char *input) {
if (input == NULL) return NULL;
size_t len = strlen(input);
char *result = (char*)malloc(len + 1);
if (result == NULL) return NULL;
// 处理换行符(fgets会保留)
len = (input[len-1] == '\n') ? len-1 : len;
for (size_t i = 0; i < len; i++) {
result[i] = input[len-1-i];
}
result[len] = '\0';
return result;
}
int main() {
char buffer[1024];
printf("输入字符串: ");
if (fgets(buffer, sizeof(buffer), stdin) == NULL) {
fprintf(stderr, "输入错误\n");
return 1;
}
char *reversed = reverse_string_advanced(buffer);
if (reversed) {
printf("逆序结果: %s\n", reversed);
free(reversed);
}
return 0;
}
在基础版本的reverse_string函数中,我们使用了经典的"双指针夹逼"法:
这种写法展示了C语言指针运算的本质——指针就是内存地址,加减运算就是在内存中移动。
两个关键点需要注意:
常见错误示例:
c复制char *str = malloc(strlen(input)); // 忘记+1
strcpy(str, input); // 可能越界
使用fgets而不是gets的原因:
当程序出现段错误时,按以下步骤排查:
在Linux下可以使用valgrind工具:
bash复制valgrind --leak-check=full ./your_program
典型的内存泄漏场景:
必须测试的边界情况:
完成本练习后,可以尝试:
哈工大推荐的C代码风格:
这个练习最精妙之处在于,它用短短几十行代码就让你直面C语言最核心也最容易出错的概念。我建议每个完成这个练习的同学都记录下自己遇到的错误和解决过程,这些经验比单纯写出正确答案宝贵得多。