我收到了以下代码:
char buffer[2047];
int charsRead;
do {
if(fscanf(file, "%2047[^\n]%n%*c", buffer, &charsRead) == 1) {
// Do something
}
} while (charsRead == 2047);
我想将此代码转换为使用动态分配的变量,以便在调用此代码时,我不会遇到大量内存泄漏。因此,我尝试了这个:
char *buffer = malloc(sizeof(char) * 2047);
int *charsRead = malloc(sizeof(int));
do {
if(fscanf(file, "%2047[^\n]%n%*c", *buffer, charsRead) == 1) {
// Do something
}
} while (*charsRead == 2047);
不幸的是,这不起作用。我总是得到“EXC_BAD_ACCESS”错误,就在使用fscanf调用的if语句之前。 我做错了什么?
感谢您的帮助!
- Ry
答案 0 :(得分:5)
原始代码泄漏的可能性远远小于新代码,因为编译器正在为您管理内存,但如果您认为必须,请更改为:
if(fscanf(file, "%2047[^\n]%n%*c", buffer, charsRead) == 1) {
你不想在这里取消引用缓冲区,比你在第一段代码中所做的更多。这样做会给你缓冲区中的第一个字符,但你想要缓冲区的地址。
答案 1 :(得分:1)
最好使缓冲区至少比您希望读取的字符数长一个字节,以便您也可以保留终止NUL。除此之外,原件不会泄漏;一旦包含代码的函数返回,那些变量就消失了。如果它有泄漏,它必须是你没有向我们展示的东西。
答案 2 :(得分:1)
要回答“我做错了什么”,您将取消引用您的buffer
指针。由于它被声明为char *
,当你写*buffer
时你得到缓冲区中的第一个字符,你想要整个事情所以只需从前面删除*
,就像这样:
if(fscanf(file, "%2047[^\n]%n%*c", buffer, charsRead) == 1) {
但是,你似乎有一个错误的前提。在第一个代码片段中使用静态分配(在堆栈上)数组不会“泄漏内存”。恰恰相反,因为你的第二个代码片段中没有任何释放,那就是泄漏内存的代码。如果你在编译时知道数组需要的大小(在这种情况下,2047),那么你应该(通常,总是存在异常,但你还没有那么高级)使用静态数组而不是动态分配之一。
答案 3 :(得分:1)
我发现您的代码存在三个问题。首先,要回答您提出的问题,您应该将buffer
而不是*buffer
作为第三个参数传递给fscanf
。尼尔的答案很好地解释了原因。
其次,你有一个缓冲区溢出。 fscanf
会自动将空终止字符附加到扫描输入。您为fscanf
提供的缓冲区必须有足够的空间用于扫描输入和空终止字符。如果要扫描2,047个字符,则缓冲区长度需要为2,048个字符。
第三,新版本的代码是内存泄漏的代码。您之前的版本没有泄漏,因为那里的缓冲区已在堆栈上分配(如果是全局变量,则在静态存储中)。当函数返回时,缓冲区使用的堆栈空间将被回收。使用malloc
从堆中分配缓冲区意味着你负责通过在完成缓冲区后调用free
来回收分配的堆内存。在我看来,你在堆栈上分配buffer
的代码的原始版本要好得多。
新版本可能更适合的唯一情况是,如果您的目标是具有非常有限的堆栈空间的系统(如某些嵌入式系统的情况)。在这样的系统上,在堆栈上分配大缓冲区可能不是一个好主意。在这种情况下,最好使用malloc
从堆中分配缓冲区,以避免可能的堆栈溢出。如果是这种情况,那么必须小心避免内存泄漏,方法是调用free
取消分配内存。
答案 4 :(得分:0)
通过动态分配charsRead,您无法完成任何事情。回到之前你有过charsRead的方式,这可能会解决你的问题。