C 编写getline()实现-Valgrind错误
我必须重新编码C 编写getline()实现-Valgrind错误,c,memory,valgrind,getline,C,Memory,Valgrind,Getline,我必须重新编码getline()函数的实现,但要使用文件的文件描述符,而不是文件*。我只允许使用malloc()和free(),以及5个最多25行的函数。 我认为我已经正确地完成了这个项目,尽管我是C语言的初学者,我的代码可能不太好 当我运行它时,它工作得很好,但是valgrind显示我确实丢失了x字节,x取决于文件长度和读取大小(在头中定义的宏) 根据valgrind的--leak check=full,我在mallocdest时,在str\u realloc\u cat函数中有内存泄漏。我试
getline()
函数的实现,但要使用文件的文件描述符,而不是文件*
。我只允许使用malloc()
和free()
,以及5个最多25行的函数。
我认为我已经正确地完成了这个项目,尽管我是C语言的初学者,我的代码可能不太好
当我运行它时,它工作得很好,但是valgrind显示我确实丢失了x字节,x取决于文件长度和读取大小(在头中定义的宏)
根据valgrind的--leak check=full
,我在mallocdest
时,在str\u realloc\u cat
函数中有内存泄漏。我试过了,但找不到我应该在哪里释放/做些别的事情
下面是我的代码:
char *get_next_line(const int fd)
{
static char *remaining = "";
char *buffer;
ssize_t cread;
size_t i;
i = 0;
if (remaining == NULL)
return (NULL);
if ((buffer = malloc(SOF(char) * READ_SIZE + 1)) == NULL ||
(cread = read(fd, buffer, READ_SIZE)) < 0)
return (NULL);
buffer[cread] = 0;
remaining = str_realloc_cat(remaining, buffer);
while (remaining[i])
{
if (remaining[i] == 10)
{
remaining[i] = 0;
buffer = str_create_cpy(remaining);
remaining = remaining + i + 1;
return (buffer);
}
i++;
}
return (check_eof(fd, buffer, remaining, cread));
}
char *str_realloc_cat(char *rem, char *buf)
{
size_t i;
size_t dest_i;
char *dest;
i = (dest_i = 0);
if ((dest = malloc(SOF(char) * (str_len(rem) + str_len(buf) + 1))) == NULL)
return (NULL);
while (rem[i])
{
dest[dest_i] = rem[i];
dest_i++;
i++;
}
i = 0;
while (buf[i])
{
dest[dest_i] = buf[i];
dest_i++;
i++;
}
dest[dest_i] = 0;
free(buf);
return (dest);
}
char *check_eof(const int fd, char *buffer, char *remaining, ssize_t cread)
{
if (cread == 0)
return (NULL);
if (cread < READ_SIZE)
{
buffer = remaining;
remaining = NULL;
return (buffer);
}
return (get_next_line(fd));
}
char *str_create_cpy(const char *src)
{
char *dest;
size_t i;
i = 0;
if ((dest = malloc(sizeof(char) * str_len(src) + 1)) == NULL)
return (NULL);
while (src[i])
{
dest[i] = src[i];
i++;
}
dest[i] = 0;
return (dest);
}
int str_len(const char *str)
{
size_t i;
i = 0;
while (str[i])
i++;
return (i);
}
我关注这一行:
remaining = remaining + i + 1;
remaining
是指向已分配缓冲区的指针。在这一行中,你破坏了它,这意味着你不能再释放它了。我担心这一行:
remaining = remaining + i + 1;
remaining
是指向已分配缓冲区的指针。在这一行中,您销毁了它,这意味着您不能再释放它了。您的算法不好:
将缓冲区保存在分配内存中
您不需要使用结构来重新组合变量
您使用的是幻数剩余[i]==10
您可以使用递归堆栈溢出返回get\u next\u line(fd)
。没关系,我读得不太好,你有一个尾部递归,只是要确保在编译过程中对它进行优化
你有意大利面密码
等等
您应该使用更好的逻辑重写整个函数,首先使用以下结构:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GNL_SIZE 4096
struct gnl_context {
char buffer[GNL_SIZE];
size_t i;
size_t read;
};
char *get_next_line_r(int fd, struct gnl_context *gnl_context);
char *get_next_line(int fd);
static char *read_buffer(struct gnl_context *gnl_context, char *str,
size_t *size) {
size_t i = gnl_context->i;
while (i < gnl_context->read && gnl_context->buffer[i] != '\n') {
i++;
}
size_t j = i - gnl_context->i;
char *ret = realloc(str, *size + j + 1);
if (ret == NULL) {
return NULL;
}
memcpy(ret + *size, gnl_context->buffer + gnl_context->i, j);
*size += j;
ret[*size] = '\0';
gnl_context->i = i;
return ret;
}
char *get_next_line_r(int fd, struct gnl_context *gnl_context) {
char *str = NULL;
size_t size = 0;
loop:
if (gnl_context->i == gnl_context->read) {
ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE);
if (ret <= 0) {
return str;
}
gnl_context->read = (size_t)ret;
gnl_context->i = 0;
}
char *tmp = read_buffer(gnl_context, str, &size);
if (tmp == NULL) {
return str;
}
if (gnl_context->i != gnl_context->read) {
gnl_context->i++;
return tmp;
}
str = tmp;
goto loop;
}
char *get_next_line(int fd) {
static struct gnl_context gnl_context;
return get_next_line_r(fd, &gnl_context);
}
int main(void) {
char *str;
while ((str = get_next_line(0)) != NULL) {
printf("%s\n", str);
free(str);
}
}
#包括
#包括
#包括
#包括
#定义GNL_尺寸4096
结构gnl_上下文{
字符缓冲区[GNL_大小];
尺寸i;
尺寸不可读取;
};
char*get_next_line_r(int fd,struct gnl_context*gnl_context);
字符*获取下一行(int fd);
静态char*read\u缓冲区(struct gnl\u context*gnl\u context,char*str,
尺寸(t*尺寸){
size\u ti=gnl\u context->i;
而(iread&&gnl\u context->buffer[i]!='\n'){
i++;
}
size\u t j=i-gnl\u context->i;
char*ret=realloc(str,*size+j+1);
if(ret==NULL){
返回NULL;
}
memcpy(ret+*size,gnl_上下文->缓冲区+gnl_上下文->i,j);
*尺寸+=j;
ret[*size]='\0';
gnl_上下文->i=i;
返回ret;
}
char*get_next_line_r(int fd,结构gnl_context*gnl_context){
char*str=NULL;
大小\u t大小=0;
循环:
如果(gnl_上下文->i==gnl_上下文->读取){
ssize_t ret=read(fd,gnl_上下文->缓冲区,gnl_大小);
if(ret read=(size_t)ret;
gnl_上下文->i=0;
}
char*tmp=read\u缓冲区(gnl\u上下文、str和size);
if(tmp==NULL){
返回str;
}
如果(gnl_上下文->i!=gnl_上下文->读取){
gnl_上下文->i++;
返回tmp;
}
str=tmp;
后藤环;
}
字符*获取下一行(int fd){
静态结构gnl_上下文gnl_上下文;
返回get_next_line_r(fd和gnl_上下文);
}
内部主(空){
char*str;
while((str=get_next_line(0))!=NULL){
printf(“%s\n”,str);
自由基(str);
}
}
您的算法不好:
将缓冲区保存在分配内存中
您不需要使用结构来重新组合变量
您使用的是幻数剩余[i]==10
您可以使用递归堆栈溢出return get\u next\u line(fd)
。没关系,我读得不太好,您有一个尾部递归,请确保在编译时对其进行优化
你有意大利面密码
等等
您应该使用更好的逻辑重写整个函数,首先使用以下结构:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define GNL_SIZE 4096
struct gnl_context {
char buffer[GNL_SIZE];
size_t i;
size_t read;
};
char *get_next_line_r(int fd, struct gnl_context *gnl_context);
char *get_next_line(int fd);
static char *read_buffer(struct gnl_context *gnl_context, char *str,
size_t *size) {
size_t i = gnl_context->i;
while (i < gnl_context->read && gnl_context->buffer[i] != '\n') {
i++;
}
size_t j = i - gnl_context->i;
char *ret = realloc(str, *size + j + 1);
if (ret == NULL) {
return NULL;
}
memcpy(ret + *size, gnl_context->buffer + gnl_context->i, j);
*size += j;
ret[*size] = '\0';
gnl_context->i = i;
return ret;
}
char *get_next_line_r(int fd, struct gnl_context *gnl_context) {
char *str = NULL;
size_t size = 0;
loop:
if (gnl_context->i == gnl_context->read) {
ssize_t ret = read(fd, gnl_context->buffer, GNL_SIZE);
if (ret <= 0) {
return str;
}
gnl_context->read = (size_t)ret;
gnl_context->i = 0;
}
char *tmp = read_buffer(gnl_context, str, &size);
if (tmp == NULL) {
return str;
}
if (gnl_context->i != gnl_context->read) {
gnl_context->i++;
return tmp;
}
str = tmp;
goto loop;
}
char *get_next_line(int fd) {
static struct gnl_context gnl_context;
return get_next_line_r(fd, &gnl_context);
}
int main(void) {
char *str;
while ((str = get_next_line(0)) != NULL) {
printf("%s\n", str);
free(str);
}
}
#包括
#包括
#包括
#包括
#定义GNL_尺寸4096
结构gnl_上下文{
字符缓冲区[GNL_大小];
尺寸i;
尺寸不可读取;
};
char*get_next_line_r(int fd,struct gnl_context*gnl_context);
字符*获取下一行(int fd);
静态char*read\u缓冲区(struct gnl\u context*gnl\u context,char*str,
尺寸(t*尺寸){
size\u ti=gnl\u context->i;
而(iread&&gnl\u context->buffer[i]!='\n'){
i++;
}
size\u t j=i-gnl\u context->i;
char*ret=realloc(str,*size+j+1);
if(ret==NULL){
返回NULL;
}
memcpy(ret+*size,gnl_上下文->缓冲区+gnl_上下文->i,j);
*尺寸+=j;
ret[*size]='\0';
gnl_上下文->i=i;
返回ret;
}
char*get_next_line_r(int fd,结构gnl_context*gnl_context){
char*str=NULL;
大小\u t大小=0;
循环:
如果(gnl_上下文->i==gnl_上下文->读取){
ssize_t ret=read(fd,gnl_上下文->缓冲区,gnl_大小);
if(ret read=(size_t)ret;
gnl_上下文->i=0;
}
char*tmp=read\u缓冲区(gnl\u上下文、str和size);
if(tmp==NULL){
返回str;
}
如果(gnl_上下文->i!=gnl_上下文->读取){
gnl_上下文->i++;
返回tmp;
}
str=tmp;
后藤环;
}
字符*获取下一行(int fd){
静态结构gnl_上下文gnl_上下文;
返回get_next_line_r(fd和gnl_上下文);
}
内部主(空){
char*str;
while((str=get_next_line(0))!=NULL){
printf(“%s\n”,str);
自由基(str);
}
}
sizeof(char)
总是1,不要用它污染你的代码。使用#define SOF(x)sizeof(x)
-不是显示而是推断出来的-似乎有点毫无意义。它可以在每次调用中节省3个字符,但会造成混乱。这不是一个很好的折衷办法。“在另一个系统上,一个char超过1个字节(尽管不太可能)。”唯一可能发生这种情况的方法是,如果C编译器不符合标准。sizeof(char)
根据C标准为1,它永远不依赖于系统。if(!av[1])
是检查是否没有参数的错误方法。虽然av
数组以null结尾,但只能保证av[ac]
将为空。在某些环境中,ac
可能为0