I'm trying to learn C (which is freaking hard...) so I wanted to write a routine which gets a line of a file. I created this function :
int c;
int buflen = 100;
if((*buffer = malloc(sizeof(char) * buflen)) == NULL) {
DXLogWarn("Not enough memory");
return;
}
char * dst = *buffer;
char * end = *buffer + buflen - 1;
while ((c = getc(fp)) != EOF) {
if (c == '\n') {
break;
}
if (dst < end) {
*dst++ = c;
}
}
*dst = '\0';
Which works yay! But now I thought instead of cutting of the last part of the string I could realloc the buffer and continue till the '\n'. So I changed it to this:
void fget_line(FILE *fp, char **buffer) {
int c;
int buflen = 10;
if((*buffer = malloc(sizeof(char) * buflen)) == NULL) {
DXLogWarn("Not enough memory");
return;
}
char * dst = *buffer;
char * end = *buffer + buflen - 1;
while ((c = getc(fp)) != EOF) {
if (c == '\n') {
break;
}
if (dst < end) {
*dst++ = c;
} else {
buflen *= 2;
*buffer = realloc(*buffer, buflen * sizeof(char));
if (*buffer == NULL) {
DXLogError("Err");
return;
}
}
}
*dst = '\0';
}
Which gives me an error : malloc: * error for object 0x10a8001b8: incorrect checksum for freed object - object was probably modified after being freed.
* set a breakpoint in malloc_error_break to debug
Which I do not get. What am I doing wrong?
at the start you do:
char * dst = *buffer;
char * end = *buffer + buflen - 1;
This set dst and end to the correct positions inside buffer. Then you reallocate buffer:
*buffer = realloc(*buffer, buflen * sizeof(char));
This causes buffer to get a new value which is probably different then before. So you also have to update dst and end to the new positions inside buffer.
Changing end is easy, but because you keep changing dst, it is difficult to calculate the new value. So instead of changing the pointers, it might be easier to store just the offset in a integer. Something like:
int pos=0;
while ((c = getc(fp)) != EOF) {
if (c == '\n') {
break;
}
if (pos >= buflen-1) {
buflen *= 2;
*buffer = realloc(*buffer, buflen * sizeof(char));
if (*buffer == NULL) {
DXLogError("Err");
return;
}
}
(*buffer)[pos] = c;
pos++;
}
(*buffer)[pos] = '\0';
I also changed the if statement above, as you did not store the character which caused the reallocation.
Related
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.
I've been trying to figure out what the problem is for hours and can't get it right. Here is the code, which is of course a lot longer but I've reduced it to the problem itself.
#define BUFFER_SIZE 60
char *str;
void readText() {
char read_char;
int i = 0;
str = (char *) calloc(BUFFER_SIZE, sizeof(char));
while ((read_char = getchar()) != EOF) { /* user hits ctrl+d */
*(str+i) = read_char;
i++;
if (i % BUFFER_SIZE == 0) {
str = (char *) realloc(str, BUFFER_SIZE * sizeof(char));
}
}
textSize = i;
/* Here I print the text... same error printing or not printing */
free(str);
}
}
I only get the error when the input text exceeds the buffer size.
(edited:
if (i % BUFFER_SIZE == 0) so it makes it every time it get to 60, but the error is the same
)
Thanks
That's because you are reallocating with the same size, you need to use the new size when the string grows up:
while ((read_char = getchar()) != EOF) { /* user hits ctrl+d */
if (i >= BUFFER_SIZE) {
str = realloc(str, i);
}
*(str+i) = read_char;
i++;
}
Also, it seems that you forget to set the trailing NUL, you need it in order to build a valid (printable) string, switch to
if (i >= BUFFER_SIZE - 1) {
and
str[i] = '\0';
after the while loop.
Finally, prefer
size_t i = 0; // or better yet size_t len = 0;
over
int i = 0;
to pass the size to realloc and friends.
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';
}
I don't understand what this function do. Can anyone explain me in detail please?
char *my_getline(FILE *stream) {
char *line = NULL;
size_t pos = 0;
int c;
while ((c = getc(stream)) != EOF) {
char *newp = realloc(line, pos + 2);
if (newp == NULL) {
free(line);
return NULL;
}
line = newp;
if (c == '\n')
break;
line[pos++] = (char)c;
}
if (line) {
line[pos] = '\0';
}
return line;
}
If you can add a comment on my code, I think that will help me. I want to search a substring in a string and I found this function code.
This is the main function:
int main(void) {
char *str, *sub;
size_t len1, len2, i, count = 0;
printf("Insert string :\n");
str = my_getline(stdin);
printf("insert substring :\n");
sub = my_getline(stdin);
if (str && sub) {
len1 = strlen(str);
len2 = strlen(sub);
for (i = 0; i + len2 <= len1; i++) {
if (!memcmp(str + i, sub, len2)) {
count++;
printf("Substring found at index : %d\n", i);
}
}
printf("in the number of: %d\n", count);
if (count == 0) {
printf("Substring not found\n");
}
}
free(str);
free(sub);
return 0;
}
I understand the main function but unable to understand the logic in function my_getline.
Please help me in understanding the logic. Thanks!
char *my_getline(FILE *stream) {
// pointer to the line to be read:
char *line = NULL;
// position of the next character:
size_t pos = 0;
// single character:
int c;
while ((c = getc(stream)) != EOF) { // read 1 character at a time until EOF
// allocate a new buffer with room for the char just read + a 0 terminator
// when `line` is NULL, this is the same as `malloc()`, otherwise it
// will change the size of the allocation:
char *newp = realloc(line, pos + 2);
// check for errors:
if (newp == NULL) {
free(line);
return NULL;
}
// no errors, assign new buffer to `line`:
line = newp;
// end of line found: we're done:
if (c == '\n')
break;
// otherwise add new character to the line:
line[pos++] = (char)c;
}
// if there was *anything* to read, add 0 terminator (marks end of string):
if (line) {
line[pos] = '\0';
}
return line;
}
That's about it. Note it's horribly inefficient for two reasons: It reads only one character at a time and it calls realloc() for each and every character.
A better solution would use e.g. fgets() and increase the buffer size in reasonable chunks, for example like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define GETLINE_CHUNK 1024
static void xrealloc(void *bufPtr, size_t size)
{
void **buf = bufPtr;
void *tmp = realloc(*buf, size);
if (!tmp)
{
free(*buf);
*buf = 0;
}
*buf = tmp;
}
char *my_getline(FILE *stream)
{
// allocate first chunk:
char *buf = malloc(GETLINE_CHUNK);
if (!buf) return 0;
*buf = 0;
size_t pos = 0;
// read up to GETLINE_CHUNK bytes, until newline:
while (fgets(buf + pos, GETLINE_CHUNK, stream))
{
// look for newline:
char *nlPos = strchr(buf, '\n');
if (nlPos)
{
// found, then our line is complete
*nlPos = 0;
// shrink buffer to needed size
xrealloc(&buf, nlPos-buf+1);
return buf;
}
// set next offset to read
pos = strlen(buf);
// increase buffer size to have room for a whole other GETLINE_CHUNK:
xrealloc(&buf, pos + GETLINE_CHUNK);
if (!buf) return 0;
}
// if nothing was read, free buffer and return NULL:
if (*buf == 0)
{
free(buf);
buf = 0;
}
return buf;
}
int main(void)
{
char *line = my_getline(stdin);
if (line)
{
puts(line);
free(line);
}
else puts("no input!");
return 0;
}
Well this function gives you line, Lets go Step by Step:
char *my_getline(FILE *stream) {
char *line = NULL; //this is just pointer initialization
size_t pos = 0; //position variable definition and init
int c; //a variable to store temporary character
while ((c = getc(stream)) != EOF) //read every character till end of file
{
// To dynamically allocate memory, with reference to the
// number of character and plus '2' is just to compensate null
// character and the character(Since pos is 0)
char *newp = realloc(line, pos + 2);
if (newp == NULL) { // this is to check whether memory was alloacted properly or not.
free(line); //if not free line
return NULL;// break the program and return NULL
}
line = newp;// if memory is allocated properly store allocated memory in line pointer
if (c == '\n') //if new line is detected
break;// break the while loop
line[pos++] = (char)c; // store the character in dynamically allocated memory and new character in new location.
}
if (line) { //if line contains something then add a null character at last, to complete that string
line[pos] = '\0';
}
return line; //returns the content of line.
}
Hope this helps :)
So I'm working on a function that will use fgetc to read a line into a buffer. so I can use that buffer as I please, and then refill the buffer with the next line. My function works however I have to repeat code outside of the for loop to process the last line as shown here:
for(i = 0, c = 1; ch != EOF; i++)
{
ch = fgetc(grab);
if(ch == 0x0A)
{
/*Process Line*/
c = 1;
}
else
{
linetmp = realloc(line, (c + 1) * sizeof(char));
if(!linetmp)
{
free(line);
free(url);
printf("\nError! Memory allocation failed!");
return 1;
}
line = linetmp;
line[c - 1] = ch;
line[c] = 0x00;
c++;
}
}
/*repeat if(ch == 0x0A) statement*/
I would rather do this all in the same loop but am not sure on how I would go about doing this. Any help would be greatly appreciated!
I would recommend that you instead use getline() if you're on a POSIX system.
Also, your logic is strange since you check for EOF in the loop header only, but update ch inside the loop. That means it will run through with ch == EOF, before the loop condition is re-evaluated.
You should try putting the updating and the check together, making the loop header read like this:
for(i = 0, c = 1; (ch = fgetc()) != EOF; i++)
Also, you need to think about line separators, both '\n' (carriage return) and '\n' (line feed) can occur.
I don't think you should reallocate after each character. If you want to have the buffer at the smallest value needed, you could reallocate at the end with ( strlen() + 1); Also, there is a function fgets() which reads a line.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
int somefunc(FILE *grab)
{
int current_size = 100;
int data_size = current_size - 1;
char *url = malloc(current_size);
char *line = malloc(current_size);
char *linetmp;
int ch;
ch = fgetc(grab);
int i = 0;
int c = 0;
while (ch != EOF && ch != 0x0A )
{
i++;
if ( i > data_size )
{
current_size = current_size * 2;
data_size = current_size - 1;
linetmp = realloc(line, current_size);
if (!linetmp)
{
free(line);
free(url);
printf("\nError! Memory allocation failed!");
return 1;
}
line = linetmp;
}
line[c] = ch;
c++;
ch = fgetc(grab);
}
line[c] = '\0';
linetmp = realloc(line,strlen(line) + 1);
line = linetmp;
printf("we just read line->%s\n",line);
free(line);
free(url);
return 0;
}
int main(void)
{
char *cpFilename = "somefile.txt";
FILE *fp = fopen(cpFilename,"r");
if ( fp == NULL )
{
printf("ERROR: could not open %s\n",cpFilename);
printf("Error code: %d\n",errno);
perror("ERROR:");
return 1;
}
int return_code = somefunc(fp);
while (return_code != EOF && return_code != 1)
{
return_code = somefunc(fp);
}
fclose(fp);
}