hello guys a just need help on this, not showing the text I wrote:
This program open the file and just show on command what is inside,
if buffer is > 0 show all the text contained in file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
char *ft_strncat(char *dst, const char *src, size_t n)
{
if (n != 0) {
char *d = dst;
const char *s = src;
while (*d != 0)
d++;
do {
if ((*d = *s++) == 0)
break;
d++;
} while (--n != 0);
*d = 0;
}
return (dst);
}
char *get_next_line(int fd)
{
char buffer[2] = "";
char **line;
if( !*line )
*line = malloc(100 * sizeof(char));
*line[0] = '\0';
while( read(fd, buffer, 1) > 0 ) {
ft_strncat(*line, buffer, 1);
if( buffer[0] == '\n' )
break;
}
return (0);
}
int main(void)
{
int fd;
int ret;
fd = open("ola.txt", O_RDONLY);
if (fd < 3 && fd != 0)
return (-1);
printf("%d\n", fd);
printf("%s\n", get_next_line(fd));
return (0);
}
im trying to see the error but I cant, im a noob on C yet
thank you for help me.
line should be char *, not char **. That would only be needed if it were a function parameter that should be updated by the function.
You need to return line from the function, not 0.
You should use realloc() to grow line if the input line is longer than the size of line. Use a variable capacity to hold the current size.
There's no good reason to use ft_strncat(). Use another variable to hold the current position in line, and write the character there directly.
char *get_next_line(int fd)
{
char buffer;
size_t capacity = 100;
char *line = malloc(capacity * sizeof(char));
size_t pos = 0;
*line[0] = '\0';
while( read(fd, &buffer, 1) > 0 ) {
if (pos > capacity - 2) {
capacity += 100;
line = realloc(line, capacity);
}
line[pos++] = buffer;
if( buffer == '\n' ) {
line[pos] = '\0';
break;
}
}
return line;
}
In addition, the caller should assign the result to a variable, so it can free the memory. Otherwise you'll create lots of memory leaks when you read all the lines of the file.
Related
I am learning c programming. Below program is showing me the output, But when it execute free method . It is give me error:- free(): invalid next size (normal) . Please let me know what i am missing.
#include<stdio.h>
#include<stdlib.h>
int main() {
FILE *fp;
char r[1024];
fp = popen("/bin/ls /etc/", "r");
if (fp == NULL) {
perror("Failed to run the command");
exit(-1);
}
int totallengthread = 0, alloc_size = 1024;
char *buffer = (char*) calloc(alloc_size , sizeof(char));
int lenofbuff = 0;
while((lenofbuff=fread(r,sizeof(char),1024,fp))>0){
totallengthread += lenofbuff;
if (totallengthread >= alloc_size) {
alloc_size += 1024;
buffer = realloc(buffer, alloc_size);
}
concat(buffer, r);
}
printf("this is the output =>%s", buffer);
pclose(fp);
free(buffer);
return 0;
}
void concat(char *dest, const char *source) {
char *d = dest;
char *s = source;
while (*d != '\0') {
d++;
}
while (*s != '\0') {
*d++ = *s++;
}
*d = '\0';
}
In modern C, routines must be declared before they are used. Either move the definition of concat before main or insert a declaration of concat before main.
Change int main() to int main(void).
fread does not add a null terminator to the data read. Change char r[1024]; to char r[1025]; and, after fread, insert r[lenofbuff] = '\0'; as the first statement inside the while body.
if (totallengthread >= alloc_size) does not account for the null terminator. Change it to if (totallengthread+1 >= alloc_size)`.
In concat, change char *s = source; to const char *s = source;.
Turn on compiler warnings and pay attention to them. They should have warned you about 1 and 5 above.
After char *buffer = (char*) calloc(alloc_size, sizeof(char));, test buffer == NULL. If it is, print an error and exit. Also, a better form for this statement is char *buffer = calloc(alloc_size, sizeof *buffer);. Casting the result of calloc is not needed in C, and basing the size on the thing being allocated rather than a repetition of the type may be safer if the type is changed in the future.
Change buffer = realloc(buffer, alloc_size); to char *temp = realloc(buffer, alloc_size * sizeof *buffer); if (temp == NULL) { print message and exit } else buffer = temp;.
Attaching the corrected code suggested by Eric Postpischil. It is working fine now.
#include<stdio.h>
#include<stdlib.h>
void concat(char *dest, const char *source);
int main(void) {
FILE *fp;
char r[1024];
fp = popen("/bin/ls /etc/", "r");
if (fp == NULL) {
perror("Failed to run the command");
exit(-1);
}
int totallengthread = 0, alloc_size = 1024;
char *buffer = (char*) calloc(alloc_size, sizeof(char));
if (buffer == NULL) {
perror("Failed allocate memory");
exit(-1);
}
int lenofbuff = 0;
while ((lenofbuff = fread(r, sizeof(char), 1023, fp)) > 0) {
r[lenofbuff] = '\0';
totallengthread += lenofbuff;
if ((totallengthread) >= alloc_size) {
alloc_size += 1024;
buffer = realloc(buffer, alloc_size*sizeof(char));
if (buffer == NULL) {
perror("Failed to extend memory");
exit(-1);
}
}
concat(buffer, r);
}
printf("this is the output =>%s", buffer);
pclose(fp);
free(buffer);
return 0;
}
void concat(char *dest, const char *source) {
char *d = dest;
const char *s = source;
while (*d != '\0') {
d++;
}
while (*s != '\0') {
*d++ = *s++;
}
*d = '\0';
}
my function is reading character by character so that's why it is not working with multiple buffer size and l need help in fixing it so that it can work with any buffer size, not just 1.
so the main issue is it's supposed to work with buffer size not character by character
l have tried to read changing the buffer but it skips some characters
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#define BUFF_SIZE 32
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
int get_next_line(int fd, char **line){
static char * s_line = NULL;
static int s_max = 0;
char character[BUFF_SIZE + 1];
if(s_line == NULL)
{
s_line = (char *)malloc((BUFF_SIZE + 1) * sizeof(char));
s_max = BUFF_SIZE;
}
int len = 0;
int ret;
while ((ret = read(fd, character, BUFF_SIZE)) > 0)
{
if (character[0] == '\n'){
break;
}
s_line[len] = character[0];
len = len + 1;
if (len >= s_max)
{
char *tmp;
s_max = s_max + BUFF_SIZE;
tmp = (char *) malloc((s_max + 1) * sizeof(char));
s_line[len] = '\0';
strcpy(tmp, s_line);
free(s_line);
s_line = tmp;
}
}
if (ret < 0) { //read error, free memory and return -1
free(s_line);
return -1;
}
if (len == 0){
free(s_line); //required to release the memory after reading the entire file
s_line = NULL;
return 0;
}
s_line[len] = '\0';
*line = s_line;
return 1;
}
int main(int argc, char **argv)
{
char *txt;
int fd;
fd = open(argv[1], O_RDONLY);
while (get_next_line(fd, &txt) > 0)
{
printf("%s\n", txt);
}
printf("Done\n");
if (txt != NULL)
{
free(txt);
}
return (0);
}
l expect the output of reading the whole file, not skipping characters
like what it is doing
The character reads the string of size BUFF_SIZE. So you need to iterate over each element in the string if BUFF_SIZE > 1 and must copy it into the s_line array to copy the complete string. Otherwise the characters will be skippped.
while ((ret = read(fd, character, BUFF_SIZE)) > 0)
{
for(i=0;i<BUFF_SIZE;i++){ // for loop is added to visit every element of the character array
if (character[i] == '\n'){
s_line[len] = '\n';
break;
}
s_line[len] = character[i];
len = len + 1;
if (len >= s_max)
{
char *tmp;
s_max = s_max + BUFF_SIZE;
tmp = (char *) malloc((s_max + 1) * sizeof(char));
s_line[len] = '\0';
strcpy(tmp, s_line);
free(s_line);
s_line = tmp;
}
}}
I made a scanning function which essentially just scans in the lines of a file into a single char * called buffer. However, after a couple hundred lines are read, the program just stops working. I just get a program has stopped working pop up window. Assuming I did something wrong with memory allocation, but I am unsure what.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *scan_file(FILE *fp);
#define MAX_LINE 200
int main(void) {
FILE *fp = fopen("test.txt", "r");
char *contents = scan_file(fp);
printf("%s\n", contents);
return 0;
}
// Scan in file into a buffer. Returns a malloc-ed string
char *scan_file(FILE *fp) {
int buf_len = 1;
int contents_len = buf_len;
char *buffer = malloc(sizeof(char) * (MAX_LINE + 1));
char *contents = malloc(sizeof(char) * (buf_len + 1));
strcpy(contents, "\0");
while (fgets(buffer, MAX_LINE, fp) != NULL) {
buf_len = strlen(buffer);
contents_len += buf_len;
realloc(contents ,contents_len);
strcat(contents, buffer);
strcpy(buffer, "\0");
}
free(buffer);
return contents;
}
Code fails to use the return value form realloc()
Allocation sizes off by 1.
Repeated strcat() make for a slow (n*n) solution.
Consider using size_t for array sizes vs. int.
Rather than call the variable ...len, consider ...size to acknowledge the presence of the final null character in a string.
char *scan_file(FILE *fp) {
// int buf_len = 1;
size_t buf_size = 1;
// int contents_len = buf_len;
size_t contents_size = buf_size;
// char *buffer = malloc(sizeof(char) * (MAX_LINE + 1));
// fgets(..., MAX_LINE, ...) will only read up to MAX_LINE - 1 characters.
char *buffer = malloc(MAX_LINE);
char *contents = malloc(buf_size + 1u);
if (buffer == NULL || contents == NULL) {
fprintf(stderr, "Out of memory\n");
return EXIT_FAILURE;
}
// strcpy(contents, "\0");
contents[0] = '\0';
while (fgets(buffer, MAX_LINE, fp) != NULL) {
// buf_len = strlen(buffer);
buf_size = strlen(buffer) + 1u;
// contents_len += buf_len;
// realloc(contents ,contents_len);
void *p = realloc(contents ,contents_size + buf_size);
if (p == NULL) {
fprintf(stderr, "Out of memory\n");
return EXIT_FAILURE;
}
contents = p;
// strcat(contents, buffer);
strcpy(contents + contents_size, buffer);
// now add
contents_size += buf_size;
// Code here not truly needed, yet helps in debugging.
// strcpy(buffer, "\0");
buffer[0] = '\0';
}
free(buffer);
return contents;
}
use realloc()s return value
realloc(NULL, size) works just like malloc(size); no need to pre-allocate
avoid excessive copying and strlen()
just put the data where you want it the first (and only) time you touch it.
#include <stdio.h>
#include <stdlib.h>
char *scanfile (FILE *fp)
{
size_t size, used;
char *buff = NULL;
int ch;
for (size=used=0;; ) {
ch = getc(fp);
if (ch == EOF) break;
if (used+1 >= size) {
size_t newsize = used? 2*used: 1024 ;
char *tmp = realloc(buff, newsize);
if (!tmp) FAIL();
else {buff = tmp; size = newsize; }
}
buff[used++] = ch;
}
/* Nothing read: return NULL */
if (!used) return NULL;
buff[used++] = 0;
/* maybe realloc (shrink) buff here */
return buff;
}
I have to recode an implementation of the getline() function, but using the file descriptor of the file and not a FILE *. I am only allowed to use malloc() and free(), along with 5 functions being 25 lines long at most.
I think I've done correctly the project although I am a beginner in C and my code isn't probably good.
When I run it, it works fine, but valgrind shows that I definetely lost x bytes, x depending of the file length and the READ_SIZE (macro defined in the header).
According to valgrind's --leak-check=full, I have a memory leak in the str_realloc_cat function, when I malloc dest. I tried but couldn't find where should I free / do something else?
Here below is my code:
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);
}
And a main functon if you would like to test:
#define SOF(x) sizeof(x) // Why in the comments
int main(int ac, char **av)
{
int fd;
char *s;
UNUSED(ac);
if (!av[1])
return 1;
fd = open(av[1], O_RDONLY);
while ((s = get_next_line(fd)))
{
printf("%s\n", s);
free(s);
}
close(fd);
}
Your algorithm is bad:
You keep the buffer in a allocate memory
You don't use a structure to regroup your variable
You use magic number remaining[i] == 10
You use recursive you can stack overflow return get_next_line(fd). Never mind, I didn't read well you have a tail recursive, just be sure to have the optimization on your compile for it.
You have Spaghetti code.
etc.
You should rewrite your whole function with a better logic first use this structure:
#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);
}
}
I am concerned about this line:
remaining = remaining + i + 1;
remaining is a pointer to the allocated buffer. On this line, you destroy it, which means that you cannot free() it anymore.
I have to recode an implementation of the getline() function, but using the file descriptor of the file and not a FILE *. I am only allowed to use malloc() and free(), along with 5 functions being 25 lines long at most.
I think I've done correctly the project although I am a beginner in C and my code isn't probably good.
When I run it, it works fine, but valgrind shows that I definetely lost x bytes, x depending of the file length and the READ_SIZE (macro defined in the header).
According to valgrind's --leak-check=full, I have a memory leak in the str_realloc_cat function, when I malloc dest. I tried but couldn't find where should I free / do something else?
Here below is my code:
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);
}
And a main functon if you would like to test:
#define SOF(x) sizeof(x) // Why in the comments
int main(int ac, char **av)
{
int fd;
char *s;
UNUSED(ac);
if (!av[1])
return 1;
fd = open(av[1], O_RDONLY);
while ((s = get_next_line(fd)))
{
printf("%s\n", s);
free(s);
}
close(fd);
}
Your algorithm is bad:
You keep the buffer in a allocate memory
You don't use a structure to regroup your variable
You use magic number remaining[i] == 10
You use recursive you can stack overflow return get_next_line(fd). Never mind, I didn't read well you have a tail recursive, just be sure to have the optimization on your compile for it.
You have Spaghetti code.
etc.
You should rewrite your whole function with a better logic first use this structure:
#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);
}
}
I am concerned about this line:
remaining = remaining + i + 1;
remaining is a pointer to the allocated buffer. On this line, you destroy it, which means that you cannot free() it anymore.