1

我得到以下代码:

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);

不幸的是,这不起作用。我总是在 fscanf 调用的 if 语句之前收到“EXC_BAD_ACCESS”错误。我究竟做错了什么?

谢谢你的帮助!

-- 瑞

4

5 回答 5

5

原始代码比新代码泄漏的可能性要小得多,因为编译器正在为您管理内存,但如果您觉得必须,请更改为:

if(fscanf(file, "%2047[^\n]%n%*c", buffer, charsRead) == 1) {

您不想在这里取消引用缓冲区,就像您在第一段代码中所做的那样。这样做会给你缓冲区中的第一个字符,但你需要缓冲区的地址。

于 2010-03-27T14:35:46.260 回答
1

使缓冲区至少比您希望读取的字符数长一个字节是个好主意,这样您也可以保存终止的 NUL。除此之外,原件不会泄漏;一旦包含代码的函数返回,这些变量就消失了。如果它有泄漏,它一定是在你没有向我们展示的东西中。

于 2010-03-27T14:39:07.703 回答
1

要回答“我做错了什么”,您正在取消引用您的buffer指针。由于它被声明为char *,所以当您编写时,*buffer您将获得缓冲区中的第一个字符,您想要整个内容,因此只需*从前面删除 ,如下所示:

if(fscanf(file, "%2047[^\n]%n%*c", buffer, charsRead) == 1) {

但是,你似乎有一个错误的前提。在您的第一个代码片段中使用静态分配的(在堆栈上)数组不会“泄漏内存”。恰恰相反,因为您的第二个代码片段中没有任何空闲,这就是会泄漏内存的代码。如果您在编译时知道数组需要的大小(在本例中为 2047),那么您应该(通常,总是有例外,但您还没有那么先进)使用静态数组而不是动态分配一。

于 2010-03-27T14:39:28.233 回答
1

我发现您的代码存在三个问题。首先,要回答您提出的问题,您应该传递buffer而不是*buffer作为第三个参数传递给fscanf. 尼尔的回答很好地解释了原因。

其次,您有缓冲区溢出。fscanf自动将空终止字符附加到扫描的输入。您提供的缓冲区fscanf必须有足够的空间用于扫描输入空终止字符。如果要扫描 2,047 个字符,则缓冲区需要 2,048 个字符长。

第三,您的代码的新版本存在内存泄漏。您以前的版本没有泄漏,因为那里的缓冲区是在堆栈上分配的(如果它是全局变量,则在静态存储中)。当函数返回时,缓冲区使用的堆栈空间将被回收。通过使用从堆中分配缓冲区malloc意味着free有责任通过在缓冲区完成后随后调用来回收分配的堆内存。在我看来,您buffer在堆栈上分配的原始代码版本要好得多。

新版本可能更可取的唯一情况是,如果您的目标是堆栈空间非常有限的系统(如某些嵌入式系统的情况)。在这样的系统上,在堆栈上分配一个大缓冲区可能不是一个好主意。在这种情况下,最好使用 来从堆中分配缓冲区malloc,以避免可能的堆栈溢出。如果是这种情况,那么您必须通过调用deallocate memory来小心避免内存泄漏free

于 2010-03-27T15:16:18.363 回答
0

通过使 charsRead 动态分配,您不会完成任何事情。回到您之前使用 charsRead 的方式,也许这会解决您的问题。

于 2010-03-27T14:39:09.623 回答