int main()
{
//FILE *out = fopen("keimeno.txt", "w+");
FILE *in = fopen("keimeno.txt", "r");
int fullbufflen=0 , i;
char buffer[100];
fgets(buffer, 100, in);
int bufflen = strlen(buffer);
char *text;
text =calloc(bufflen,sizeof(char));
char *strcat(text, buffer);
// printf("line of \"keimeno.txt\": %s", buffer);
// printf("size of line \"keimeno.txt\": %i\n\n", bufflen);
fullbufflen = bufflen;
while(fgets(buffer, 100, in)!=NULL)
{
// printf("line of \"keimeno.txt\": %s", buffer);
// printf("size of line \"keimeno.txt\": %i\n\n", bufflen);
text =realloc(text,bufflen*sizeof(char));
char *strcat(text, buffer);
fullbufflen = bufflen + fullbufflen ;
}
for (i = 0;i<fullbufflen;i++)
{
printf("%c\n",text[i]);
}
}
I am trying to copy the full text file (keimeno.txt) into a dynamic memory array, with a buffer of 100 character at most everytime. To test it at the end i tried to prinf the results. And i just cant get it to work. Dont know if there is a problem on the printf at the end, or the whole program is just wrong.
Also the dynamic array is supposed to have 0 size at the beggining, so if someone could tell me how to do that too, it would be welcome.
Thanks in advance.
There are a few issues:
char *strcat(text, buffer);
This is not how you call a function. This is a function declaration, and an incorrect one at that since it doesn't define the types of the arguments.
To call strcat, just do this:
strcat(text, buffer);
Next, you're not allocating enough space for your buffers:
text =calloc(bufflen,sizeof(char));
You need to add space for the null bytes that terminates the string:
text =calloc(bufflen + 1,sizeof(char));
Similarly here:
text =realloc(text,bufflen*sizeof(char));
This only reallocates a total of bufflen bytes. It does not add bufflen bytes to what was already allocated, and bufflen is unchanged from when it was first set outside of the while loop. Do this instead:
bufflen = strlen(buffer);
text =realloc(text,bufflen+fullbufflen+1);
This gives you enough space for the current length, the additional buffer, and the null byte.
Finally, make sure you fclose(in) and free(text) at the end to clean up your resources, and be sure to check the return value of fopen to ensure that the file opened successfully, and realloc/calloc to ensure that your allocations worked.
After the above changes, you code should look like this:
int main(void)
{
//FILE *out = fopen("keimeno.txt", "w+");
FILE *in = fopen("keimeno.txt", "r");
if (in == NULL) {
perror("open failed");
exit(1);
}
int fullbufflen=0 , i;
char buffer[100];
fgets(buffer, 100, in);
int bufflen = strlen(buffer);
char *text;
text =calloc(bufflen+1,sizeof(char));
if (text == NULL) {
perror("calloc failed");
exit(1);
}
strcat(text, buffer);
// printf("line of \"keimeno.txt\": %s", buffer);
// printf("size of line \"keimeno.txt\": %i\n\n", bufflen);
fullbufflen = bufflen;
while(fgets(buffer, 100, in)!=NULL)
{
// printf("line of \"keimeno.txt\": %s", buffer);
// printf("size of line \"keimeno.txt\": %i\n\n", bufflen);
bufflen = strlen(buffer);
text =realloc(text,bufflen+fullbufflen+1);
if (text == NULL) {
perror("realloc failed");
exit(1);
}
strcat(text, buffer);
fullbufflen = bufflen + fullbufflen ;
}
fclose(in);
for (i = 0;i<fullbufflen;i++)
{
printf("%c\n",text[i]);
}
free(text);
}
Here is one possible solution:
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#define ERR (-1)
#define GROW 100
static void die ( const char * msg ) { perror(msg); exit(1); }
int main ( void ) {
char * filename = "in.txt";
size_t buffSize = 0;
size_t buffUsed = 0;
ssize_t bytesRead = 0;
char * buffer = NULL;
char * tmp;
int fd;
fd = open(filename, O_RDONLY, 0);
if (fd == ERR) die("open");
do {
buffUsed += (size_t)bytesRead;
if (buffUsed == buffSize) {
tmp = realloc(buffer, buffSize += GROW);
if (tmp == NULL) die("realloc");
buffer = tmp;
}
bytesRead = read(fd, buffer + buffUsed, buffSize - buffUsed);
if (bytesRead == ERR) die("read");
} while (bytesRead > 0);
if (write(STDOUT_FILENO, buffer, buffUsed) == ERR) die("write");
free(buffer);
if (close(fd) == ERR) die("close");
return 0;
}
Like the original, the input filename is hard-coded which sub-optimal...
Related
I want the following code to accomplish to store the content of the file it reads in a variable
content without leaking memory:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
char* concat(const char *s1, const char *s2)
{
const size_t len1 = strlen(s1);
const size_t len2 = strlen(s2);
char *result = malloc(len1 + len2 + 1);
memcpy(result, s1, len1);
memcpy(result + len1, s2, len2 + 1);
return result;
}
int main() {
char path[] = "/home/jim/trackers_best.txt";
FILE *archivo = fopen(path,"r");
char line[200];
char * content = "";
if (archivo == NULL)
exit(1);
else {
fseek(archivo, 0L, SEEK_END);
int sz = ftell(archivo);
fseek(archivo, 0L, SEEK_SET);
if (sz < pow(10, 7) ) {
printf("\nThe content of %s is:\n", path);
while (feof(archivo) == 0) {
fgets(line, 200, archivo); //reads one line at a time - comment out the while loop to find out
content = concat(content, line);
//free(content);//No leaks but no content either
}
}
else {
puts("File take up more than 10 MBs, I refuse to read it.");
fclose(archivo);
exit(0);
}
}
fclose(archivo);
puts(content);
free(content);
return 0;
}
much the same as this code that uses fread() does it:
#include<stdio.h>
#include<stdlib.h>
#include <math.h>
#include <sys/types.h>
int main() {
int count;
char path[] = "/home/jim/trackers_best.txt";
FILE *archivo = fopen(path,"rb");
if (archivo == NULL) {
puts("Does not exist.");
exit(1);
}
else {
fseek(archivo, 0L, SEEK_END);
int sz = ftell(archivo);
char contenido[sz];
fseek(archivo, 0L, SEEK_SET);
if (sz < pow(10, 7) ) {
count = fread(&contenido, 10 * sizeof(char), sz, archivo);//reads 10 characters at a time.
}
else {
puts("File take up more than 10 MBs, I refuse to read it.");
}
fclose(archivo);
// Printing data to check validity
printf("Data read from file: %s \n", contenido);
printf("Elements read: %i, read %li byte at a time.\n", count, 10 * sizeof(char));
}
return 0;
}
The first code snippet leaks memory, as evidenced by valgrind:
...
total heap usage: 44 allocs, 4 frees, 23,614 bytes allocated
...
==404853== LEAK SUMMARY:
==404853== definitely lost: 17,198 bytes in 40 blocks
...
When I attempt to prevent such leak by executing free() within the while loop I get no value stored in content. How might I store the string read by fgets without leaking memory?
When you call concat the second time, the value from the first call is overwritten by the malloc call. That is the memory leak.
I presume that you want content to be one long string that contains the data from all lines.
You want to use realloc (vs. malloc) in concat and just append s2 to the enlarged s1.
With this modified scheme, instead of char *content = "";, you want: char *content = NULL;
Also, don't use feof
And, ftell returns long and not int. And, it's better to not use pow to compare against the limit.
Here is the refactored code (I've compiled it but not tested it):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
char *
concat(char *s1, const char *s2)
{
size_t len1;
size_t len2;
if (s1 != NULL)
len1 = strlen(s1);
else
len1 = 0;
len2 = strlen(s2);
s1 = realloc(s1,len1 + len2 + 1);
if (s1 == NULL) {
perror("realloc");
exit(1);
}
memcpy(s1 + len1, s2, len2 + 1);
return s1;
}
int
main(void)
{
char path[] = "/home/jim/trackers_best.txt";
FILE *archivo = fopen(path, "r");
char line[200];
#if 0
char *content = "";
#else
char *content = NULL;
#endif
if (archivo == NULL)
exit(1);
fseek(archivo, 0L, SEEK_END);
long sz = ftell(archivo);
fseek(archivo, 0L, SEEK_SET);
if (sz < (10 * 1024 * 1024)) {
printf("\nThe content of %s is:\n", path);
while (fgets(line, sizeof(line), archivo) != NULL)
content = concat(content, line);
}
else {
puts("File take up more than 10 MBs, I refuse to read it.");
fclose(archivo);
exit(0);
}
fclose(archivo);
if (content != NULL)
puts(content);
free(content);
return 0;
}
You knew what you needed to do but didnt do it right
content = concat(content, line);
//free(content);//No leaks but no content either
you need to keep the old content pointer so you can delete it after you create a new one
char *oldc = content;
content = concat(content, line);
free(oldc);
Here, I am trying to read from a text file, copy this file into an array, then I want to write the array to another text file. This is not copying into the array at all. I am just getting blank values when I print.
int main(void)
{
char char_array[50];
char copied_array[50];
//int n = 2;
FILE* fpointer = fopen("hello_world.txt", "r");
FILE* fpointer2 = fopen("copyhello.txt", "w");
for(int i = 0;i < 50; i++)
{
fread(&char_array, sizeof(char), 1, fpointer);
copied_array[i] = char_array[i];
}
for(int j = 0;j < 50; j++)
{
printf("char_array: %c\n", copied_array[j]);
}
fclose(fpointer);
fclose(fpointer2);
}
working code. hope this becomes clearer :)
Note you're using fread/fwrite - compare with fgets/fputs for strings.
#include "stdio.h"
#include "string.h"
#define BUFSIZE 50
// memory size 'plus one' to leave room for a string-terminating '\0'
#define BUFMEMSIZE (BUFSIZE+1)
const char *file1 = "hello_world.txt";
const char *file2 = "copyhello.txt";
int main(void)
{
char char_array[BUFMEMSIZE];
char copied_array[BUFMEMSIZE];
FILE *fInput, *fOutput;
fInput = fopen(file1, "r");
if(fInput != NULL)
{
fOutput = fopen(file2, "w");
if(fOutput != NULL)
{
// make sure memory is wiped before use
memset(char_array, 0, BUFMEMSIZE);
memset(copied_array, 0, BUFMEMSIZE);
size_t lastSuccessfulRead = 0;
// the read-then-loop pattern: try and read 50 chars
size_t bytesRead = fread(char_array, sizeof(char), BUFSIZE, fInput);
while(bytesRead != 0)
{
// we got at least 1 char ..
// (to be used at end - so we know where in char_array is the last byte read)
lastSuccessfulRead = bytesRead;
// 'bytesRead' bytes were read : copy to other array
strncpy(copied_array, char_array, bytesRead);
// write to output file, number of bytes read
fwrite(copied_array, sizeof(char), bytesRead, fOutput);
// read more, and loop, see if we got any more chars
bytesRead = fread(char_array, sizeof(char), BUFSIZE, fInput);
}
// set char after the last-read-in char to null, as a string-terminator.
char_array[lastSuccessfulRead] = '\0';
// an array of chars is also a 'string'
printf("char_array: %s\n", char_array);
fclose(fOutput);
}
else printf("cant open %s\n", file2);
fclose(fInput);
}
else printf("cant open %s\n", file1);
}
My code is not putting the text file data into line on the second pass of the while loop, and any subsequent pass. I'm sure it's a silly error but I cannot find it.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE *fr;
char *line,*word,*vali;
ssize_t read;
int i=0,sum=0,len =0,flag=0;
const char delim[2]=" ";
int main(int argc, char* argv[])
{
line = (char *)malloc(sizeof(&len));
word = (char *)malloc(sizeof(&len));
vali = (char *)malloc(sizeof(&len));
fr = fopen(argv[1], "r");
if(fr==NULL)
{
exit(EXIT_FAILURE);
}
while ((read = getline(&line, &len, fr)) != -1)
{
printf("line is %s\n", line );
fscanf(fr,"%s%*[^\n]",word);
printf("%s ", word);
vali=strtok(line, delim);
while(vali != NULL)
{
sum=sum+atoi(vali);
vali = strtok(NULL, delim);
}
printf("%d\n", sum);
sum=0;
vali=" ";
len = strlen(line);
}
fclose(fr);
if (line)
free(line);
return 0;
}
If len is some integral type containing the desired length of the first line, then:
&len
Has type pointer-to-integer, and
sizeof(&len)
Returns the size of a pointer (8 bytes on most 64 bit systems) and
malloc(sizeof(&len))
Allocates only 8 bytes of memory (or whatever pointer size is on your system).
This is probably at least part of the issue.
I'm just getting into C and I figured this would be a good exercise. I've been putsing around with fgets trying to read from a file and I am just doing something wrong. I would like to enter the file name to read, enter the file name to output to, create that file, sort it (just a list of words), and then dump the sorted list into the created file. I know I should be doing something like:
char strIn[25];
printf("Enter a source filename: ");
fgets(strIn, 25, stdin);
printf("You entered: %s \n", strIn);
FILE *infile;
infile = fopen(strIn, "r");
if (infile == NULL){
printf("Unable to open file.");
}
char strOut[25];
printf("Enter a destination filename: ");
fgets(strOut, 25, stdin);
printf("You entered: %s \n", strOut);
FILE *outfile;
Any help is appreciated! Thank you
fgets puts the newline character \n at the end of your buffer. So you need to remove it.
int length = strlen(strIn);
if ( length > 0 && strIn[length-1] == '\n' )
strIn[length-1] = '\0';
You are on the right track. qsort will do what you want. The approach used here is not scalable; everything is held in memory and static allocation will make things HUGE very quickly, but it works as a toy example. At the moment it will break once there are more than 1000 lines in the input file.
# include <stdio.h>
# include <string.h>
#define MAXNAMELEN 100
#define MAXLINELEN 100
#define MAXITEMS 1000
int main(int argc, char ** argv) {
FILE * infile, * outfile;
// Statically allocated -- dastardly!
char name[MAXNAMELEN];
char line[MAXLINELEN];
char lines[MAXITEMS][MAXLINELEN];
int i, items = 0;
printf("Enter a source filename: ");
fgets(name, sizeof(name), stdin);
name[strlen(name)-1] = '\0'; // strip newline
// No error checking -- ANYWHERE -- dastardly!
infile = fopen(name, "r");
while (fgets(line, sizeof(line), infile)) {
strcpy(lines[items], line);
items++;
}
qsort(lines, items, MAXLINELEN, strcmp);
printf("Enter a destination filename: ");
fgets(name, sizeof(name), stdin);
name[strlen(name)-1] = '\0'; // strip newline
outfile = fopen(name, "w");
for (i=0; i<items; i++) {
fputs(lines[i], outfile);
}
fclose(infile);
fclose(outfile);
}
Now with dynamic allocation and error-checking (possibly an improvement on than the version above). Sorts /usr/share/dict/words (99171 lines) no problem at all. Still requires that the entire array be held in memory. See External Sorting for a way around that.
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
#define CHUNKLEN 100
#define INITITEMS 1000
/* Reads a string from stream into buffer until a newline or EOF.
buffer is dynamically allocated (and reallocated if necessary)
to ensure the string fits. Returns the number of characters put
into the buffer (zero if EOF and no characters read), or -1 on error. */
int unlimited_read(char ** buffer, FILE * stream) {
int bufl = CHUNKLEN;
int strl = 0;
char * chunk = (char *)malloc(CHUNKLEN);
if ( (*buffer = (char *) malloc(CHUNKLEN)) == NULL ) {
perror("memory error (malloc)");
return -1;
}
while (fgets(chunk, CHUNKLEN, stream) != NULL) {
strcpy(*buffer + strl, chunk);
strl += strlen(chunk);
if ( (strl == bufl - 1 ) && *(*buffer + strl - 1) != '\n') {
// lengthen buffer
bufl += CHUNKLEN - 1;
if ( (*buffer = realloc(*buffer, bufl)) == NULL ) {
perror("memory error (realloc)");
return -1;
}
} else {
// This shouldn't fail -- we're only ever making it smaller
*buffer = realloc(*buffer, strl);
return strl;
}
} // while
// If fgets returned NULL and we are not at EOF, it didn't work
return feof(stream) ? strl : -1;
}
/* Compare two strings given pointers to those strings.
Routine is courtesy of the qsort man page */
int cmpstringp(const void *p1, const void *p2) {
return strcmp(* (char * const *) p1, * (char * const *) p2);
}
/* Sort lines in a file. File must end with a newline. */
int main(int argc, char ** argv) {
FILE * infile, * outfile;
char * inname, * outname, *tmpstr;
char ** lines;
int ret, tmp, nlines, i, items = 0;
if (argc != 3) {
printf("Usage: %s file_to_sort output_file\n", argv[0]);
exit(EXIT_FAILURE);
}
inname = argv[1];
outname = argv[2];
if ( (lines = malloc(INITITEMS * sizeof(char *))) == NULL) {
perror("memory error (malloc)");
exit(EXIT_FAILURE);
}
nlines = INITITEMS;
infile = fopen(inname, "r");
while ((ret = unlimited_read(&lines[items], infile)) > 0) {
items++;
if (items == nlines) {
nlines += INITITEMS;
lines = realloc(lines, (nlines * sizeof(char *)));
}
}
if (ret < 0) {
printf("WARNING: possibly truncated file\n");
}
tmpstr = lines[items - 1]; // Final line in file
tmp = strlen(tmpstr);
if (tmpstr[tmp - 1] != '\n') {
printf("Error: input file does not end with newline\n");
exit(EXIT_FAILURE);
}
qsort(lines, items, sizeof(char *), cmpstringp);
outfile = fopen(outname, "w");
for (i = 0; i < items; i++) {
fputs(lines[i], outfile);
free(lines[i]);
}
free(lines);
fclose(infile);
fclose(outfile);
}
in my program, I provide a directory which contains text files. Each of the text files contain a few hundred lines in the following format
Username,Password,BloodType,Domain,Number
I then create a thread for each file in the directory which will merge-sort(by number) these lines into the array char* text_lines[6000];
I can't figure out why I'm getting a segmentation fault because I'm getting different output on every run.
Heres my code:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <dirent.h>
#include <string.h>
void store_line(char* line);
void* my_merge_sort(void* file);
char** text_lines;
int main(int argc, char* argv[])
{
if(argc != 2)
{
fprintf(stderr, "usage: ./coolsort <directory>\n");
}
else
{
text_lines = malloc(6000 * sizeof(char*));
DIR* the_directory;
int filecount = 0;
struct dirent* directory_files[50];
if((the_directory = opendir(argv[1])) != NULL)
{
//make a list of the files in the directory
while((directory_files[filecount++] = readdir(the_directory))) ;
filecount--;
//<<<DEBUGGING INFO>
int i;
fprintf(stderr,"there are %i files in %s:\n", filecount, argv[1]);
for(i = 0; i < filecount; i++)
{
fprintf(stderr, "%s\n",directory_files[i]->d_name);
}
char cwd[512];
chdir(argv[1]);
getcwd(cwd, sizeof(cwd));
fprintf(stderr, "the CWD is: %s\n", cwd);
//<DEBUGGING INFO>>>
//lets start some threads
pthread_t threads[filecount-2];
int x = 0;
for(i = 0; i < (filecount); i++ )
{
if (!strcmp (directory_files[i]->d_name, "."))
continue;
if (!strcmp (directory_files[i]->d_name, ".."))
continue;
pthread_create(&threads[x++], NULL, my_merge_sort, (void*)directory_files[i]->d_name);
}
//do stuff here
//
}
else
{
fprintf(stderr, "Failed to open directory: %s\n", argv[1]);
}
}
}
void* my_merge_sort(void* file)
{
fprintf(stderr, "We got into the function!\n");
FILE* fp = fopen(file, "r");
char* buffer;
char* line;
char delim[2] = "\n";
int numbytes;
//minimize I/O's by reading the entire file into memory;
fseek(fp, 0L, SEEK_END);
numbytes = ftell(fp);
fseek(fp, 0L, SEEK_SET);
buffer = (char*)calloc(numbytes, sizeof(char));
fread(buffer, sizeof(char), numbytes, fp);
fclose(fp);
//now read the buffer by '\n' delimiters
line = strtok(buffer, delim);
fprintf(stderr, "Heres the while loop\n");
while(line != NULL)
{
store_line(line);
line = strtok(buffer, NULL);
}
free(buffer);
}
void store_line(char* line)
{
//extract the ID.no, which is the fifth comma-seperated-token.
char delim[] = ",";
char* buff;
int id;
int i;
strtok(line, delim);
for(i = 0; i < 3; i++)
{
strtok(line, NULL);
}
buff = strtok(line, NULL);
id = atoi(buff);
//copy the line to text_lines[id]
memcpy(text_lines[id], line, strlen(line));
}
edit: I checked to make sure that it would fit into the initial array, and found that the highest ID is only 3000;
You use of strtok() is wrong:
line = strtok(buffer, NULL);
should be
line = strtok(NULL, delim);
Another mistakes should be fixed similarly.
The elements of text_lines are uninitialized:
text_lines = malloc(6000 * sizeof(char*));
this allocated 6000 pointers to char, but none of these pointers are initialized.