使用strlen与指针遇异常及函数返回char指针的技术求助
问题分析与解决方案
首先,咱们拆解你遇到的两个核心问题:
一、为什么strlen计算的字符数总是多2?
这是因为你用fgets读取文件内容时,会把每行末尾的换行符一起读进来——Windows系统下的文本文件换行是\r\n(两个字符),所以每个单词字符串末尾会多出这两个不可见字符,strlen自然会把它们算进去,导致结果比实际单词长度多2。
二、如何正确从函数返回char指针?
你当前把char*强制转成int返回的做法完全错误,会导致三个严重问题:
- 64位系统下指针长度是8字节,int是4字节,强制转换会截断地址,导致后续访问非法内存;
- 函数内malloc的二级指针
word没有被释放,造成内存泄漏; - main里两次调用
read(library),相当于每次都重新读取文件、分配内存,你打印的字符串和计算长度的字符串根本不是同一个!
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> // 读取文件并返回随机选中的单词(动态分配,需在main中free) char* read_words() { FILE *library = fopen("C:\\Users\\pc\\Desktop\\library.txt", "r"); if (library == NULL) { perror("Failed to open file"); return NULL; } // 第一步:统计单词数量 int word_count = 0; char temp_buf[256]; while (fgets(temp_buf, sizeof(temp_buf), library) != NULL) { word_count++; } rewind(library); // 第二步:分配二级指针存储所有单词 char **words = malloc(word_count * sizeof(char*)); if (words == NULL) { perror("Failed to allocate memory for words array"); fclose(library); return NULL; } for (int i = 0; i < word_count; i++) { words[i] = malloc(256 * sizeof(char)); if (words[i] == NULL) { perror("Failed to allocate memory for word"); // 内存分配失败时,先释放已分配的内存 for (int j = 0; j < i; j++) { free(words[j]); } free(words); fclose(library); return NULL; } fgets(words[i], 256, library); // 去掉末尾的\r\n或\n,截断字符串 words[i][strcspn(words[i], "\r\n")] = '\0'; } // 第三步:随机选中一个单词 int random_idx = rand() % word_count; // 分配内存拷贝选中的单词,避免释放words数组后指针失效 char *selected_word = malloc(strlen(words[random_idx]) + 1); strcpy(selected_word, words[random_idx]); // 释放临时内存,避免泄漏 for (int i = 0; i < word_count; i++) { free(words[i]); } free(words); fclose(library); return selected_word; } int main() { // 初始化随机种子,只需要执行一次 srand((unsigned int)time(NULL)); char *random_word = read_words(); if (random_word == NULL) { return 1; } int word_length = strlen(random_word); printf("选中的单词:%s\n字符数:%d\n", random_word, word_length); // 记得释放动态分配的内存 free(random_word); return 0; }
关键修改点说明
- 文件路径转义:Windows路径中的反斜杠必须写成
\\,否则会被当作转义字符处理; - 处理换行符:用
strcspn函数定位到\r或\n的位置,直接替换为字符串结束符\0,彻底去除换行符; - 正确返回指针:函数返回
char*类型,并且将选中的单词拷贝到新的动态内存中,再释放临时的二级指针数组,避免内存泄漏; - 内存安全:增加了内存分配失败的错误处理,避免程序崩溃;
- 随机种子初始化:只在main中执行一次
srand,保证随机数的有效性; - 避免重复读取:main中只调用一次读取函数,保证打印的单词和计算长度的是同一个。
内容的提问来源于stack exchange,提问作者Becker
相关产品推荐
相关产品推荐

