与scanf类似的功能中存在内存泄漏问题
在下面的代码中,我试图重新创建与scanf类似的功能中存在内存泄漏问题,c,memory,memory-management,memory-leaks,valgrind,C,Memory,Memory Management,Memory Leaks,Valgrind,在下面的代码中,我试图重新创建scanf以读取stdin中的所有内容,并在新行字符上断开,返回字符串中读取的所有字符 但问题是代码会泄漏一些内存,特别是在调用realloc时 我还想知道为什么使用get是一个危险的函数 test.c:警告:“get”函数很危险,不应使用。 我的代码:- #include <stdio.h> #include <string.h> #include <stdlib.h> #define MAX_BUF_LEN 128 #def
scanf
以读取stdin
中的所有内容,并在新行字符上断开,返回字符串中读取的所有字符
但问题是代码会泄漏一些内存,特别是在调用realloc
时
我还想知道为什么使用get
是一个危险的函数
test.c:警告:“get”函数很危险,不应使用。
我的代码:-
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_BUF_LEN 128
#define __cdecl
//0 - Success
//-1 - Error in input
//1 - Error
__cdecl int read_input(char *s,int len){
char c,*t;
int l,i=0;
if(s==NULL || len < 1)
return -1;
while((c=getchar()) != '\n'){
//check if sufficient memory
//required + used > assigned
l=strlen(s);
if(l + 2 > len){
len += l + MAX_BUF_LEN; //realloc max to avoid subsequent realloc as its costly!
t = realloc(s,len);
if(t!=NULL)
s = t;
else
return 1; //No space to store content
}
s[i++] = c;
}
s[i++] = '\0'; //Null terminate the Buffer
return 0;
}
int main(int argc,char* argv[]){
int len = 5+1;
char *s = calloc(len,sizeof(char));
printf("Enter your name\n");
if(!read_input(s,len))
printf("Hi %s\n",s);
free(s);
return 0;
}
编辑:-请参考下面随附的新代码
新代码:-
__cdecl int read_input(char **s,int len){
char c,*t;
int l,i=0;
if((*s)==NULL || len < 1)
return -1;
while((c=getchar()) != '\n'){
//check if sufficient memory
//required + used > assigned
l=strlen((*s));
if(l + 2 > len){
len += l + MAX_BUF_LEN; //realloc max to avoid subsequent realloc as its costly!
t = realloc((*s),len);
if(t!=NULL)
(*s) = t;
else
return 1; //No space to store content
}
*((*s)+i++) = c;
}
*((*s)+i) = '\0'; //Null terminate the Buffer
return 0;
}
它仍然存在一些问题。以下是关于问题的说明:
永远不要使用get()。由于无法在不事先知道数据的情况下判断GET()将读取多少个字符,并且由于GET()将继续存储超过缓冲区末尾的字符,因此使用GET()非常危险。它被用来破坏计算机安全。改用fgets()
发生泄漏问题的原因是指针s
是按值传递的,因此任何更改(包括重新分配后的赋值)都是对其副本而不是原始指针进行的。因此,释放s
只释放最初分配的内存,泄漏realloc
-ed内存。要解决此问题,请更改read\u input
以获取指向指针的指针,如下所示:
int read_input(char **ps,int len)
将&s
传递到读取输入
,并使用(*ps)
代替函数体中的s
。您的操作不会将指针返回到分配的缓冲区。所以,free(s)
并没有达到您的期望realloc
不保证在同一位置提供额外空间。因此,缓冲区可以移动。一种解决方案是将指针传递给一个指针,或者返回指针而不是int
,并使用NULL指示错误
PS-还有其他问题,这是非常不安全的代码。在循环中,您使用:
l=strlen(s);
但是s
在循环中的任何位置都没有以null结尾。因此,当您随后在上调用strlen()
时,它将无法提供您所期望的内容,这可能是内存泄漏的原因。因此,请确保在循环中以null结束字符串
gets
是危险的,因为它允许您读取的空间超过分配的空间。gets()是危险的,因为它不知道缓冲区实际有多大,因此无法防止在大输入行上缓冲区溢出。对于坏人来说,缓冲区溢出是一种非常常见的攻击向量。改用fgets()和stdin作为第一个参数,它允许您指定缓冲区的大小。好吧,这可能不是问题,但似乎您正在用\0
替换字符串的最后一个字符。不要将i++
误用为++i
或i+1
s[i++]='\0'//Null终止缓冲区
应为s[i]='\0'//Null终止缓冲区
,因为i本身会递增,所以数组以Null终止。我不再被使用,因此避免了额外的增量。calloc
zero初始化内存块,因此strlen
不会遇到问题,我想这是对的。我以为是malloc,事实并非如此。现在可以用了吗?strlen
仍然存在一些问题,我将发布一个新的答案,其中包括valgrind
结果以及我在代码中所做的更改。我理解你的意思。由于realloc
的原因,内存位置可能会按照@Judge Maygarden的建议发生变化,这将给free
造成问题。但是,如果我没有使用Realloc
,我认为这段代码会完美地工作。我说得对吗?
int read_input(char **ps,int len)
l=strlen(s);