将fscanf与动态分配的缓冲区配合使用

时间:2010-03-27 14:32:30

标签: c dynamic malloc scanf

我收到了以下代码:

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

5 个答案:

答案 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的方式,这可能会解决你的问题。