I'm writting a passing program and I have a little problem.
I want to dynamically allocate memory location with the size of the sentence which is readed from a file. Also this pointer should have this text in contents
When file will have sentence:
"One two three four five"
Then I want char* example with allocated memory location for 25 chars.
And when I would like to print this text on console I want do it by
printf("%c", example);
Console should look like that:
One two three four five
I'm doing it like that:
char* czyt = (char*)malloc(sizeof(fgets( line/*static variable*/,
500 /*MAX LINE LENGHT*/,
wejscie /*FILE*/ )));
But in this case czyt doesn't have this sentence and I need to use static variable.
If your concern is to solve this without a buffer: It's somewhat unusual. But on a POSIX-like system you could use stat() (cf. http://pubs.opengroup.org/onlinepubs/009695399/functions/stat.html).
Less efficient is to use Posix' lseek(): open the file, seek to the end with int fileLength = lseek(fd, 0, SEEK_END); and allocate fileLength bytes.
Whatever function you use, it will tell you the size of the file without reading anything so that you can then allocate a buffer of exactly the required size. Don't forget to rewind the file with lseek(fd, 0, SEEK_SET) before you read from it, or close it and open again with fopen().
The most ideal way to sort the lines of file would be to
use a dictionary tree. Create a dictionary tree with individual lines
and then perform a depth-first traversal.
Here is a simple program that would do a dynamic buffer allocation based on line length( assuming the length of line is not more than 500)
int main(int argc, char const *argv[])
{
char string[500];
char *str;
FILE *in_file = fopen("abc.txt", "r");
if (in_file == NULL)
{
printf("Error file missing\n");
exit(-1);
}
while ( fgets(string, 500, in_file) != NULL)
{
str = (char *) malloc ( sizeof(char) * strlen(string));
strcpy(str, string);
printf("%s", str);
}
fclose(in_file);
return 0;
}
In case if you want to sort them, you can either use a linked list to store these data or can use an array of pointers (which would hold the pointer address of all the malloc-ed lines) and then sort by manipulating the pointers
Related
Like I said in the title I don't know how to print all the content of a .txt file in C.
Here's an incomplete function that I did:
void
print_from_file(items_t *ptr,char filemane[25]){
char *string_temp;
FILE *fptr;
fptr=fopen(filemane, "r");
if(fptr){
while(!feof(fptr)){
string_temp=malloc(sizeof(char*));
fscanf(fptr,"\n %[a-z | A-Z | 0-9/,.€#*]",string_temp);
printf("%s\n",string_temp);
string_temp=NULL;
}
}
fclose(fptr);
}
I'm pretty sure that there's errors in the fscanf because sometimes it doesn't exit the loop.
Can anyone please correct this?
You're using malloc wrong. Passing sizeof(char*) to malloc means you are only giving your string the amount of memory it would take to hold a pointer to a character(array). So currently, by writing into memory you have not allocated, you have undefined behavior. It is also highly advisable to perform checks on file lenght and otherwise make sure that you do not write more into the string then you allocated to it.
Instead, do something like this:
string_temp=malloc(100*sizeof(char)); // Enough space for 99 characters (99 chars + '\0' terminator)
There are several things to fix in your code.
First of all, you should always check if a file has been opened correctly.
Example:
FILE *fp; //file pointer
if((fp = fopen("file.txt", "r") == NULL) { //check opening
printf("Could not open file"); //or use perror()
exit(0);
}
Also, remember that scanf() and fscanf() return the number of elements they have read. So, for example, if you scan the file one word at a time, you could simplify your program by looping while fscanf(..) == 1.
As a final note, remember to allocate dynamic memory correctly.
You do not want to allocate memory based on a pointer to char size, in fact, you're gonna wanna allocate 1 byte for each character of the string, + 1 for the terminator.
Example:
char name[55];
char * name2;
//To make them of the same size:
name2 = malloc(sizeof(*char)); **WRONG**
name2 = malloc(sizeof(char) * 55); //OK
Switching to C from Java, and I'm having some troubles grasping memory management
Say I have a function *check_malloc that behaves as such:
// Checks if malloc() succeeds.
void *check_malloc(size_t amount){
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if ( tpt == NULL ){
fprintf(stderr, "No memory of %lu bytes\n", amount);
exit(1);
}
return tpt;
}
I also have the following variables to work with:
FILE *f = fopen("abc.txt", "r"); // Pointer to a file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
}
My goal is to use *check_malloc to dynamically allocate memory so that the String pointed to by *pname is just the correct size for storing "mynamisbob", which is the only thing on the first line of the text file.
Here is my (failed) attempt:
int main(int argc, char *argv[]){
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
char *pname; // Pointer to a string for storing the name
char currentline[150]; // Char array for storing current line of file
while(!feof(f)){
fgets(currentline,100,f);
pname = ¤tline;
}
But I know this probably isn't the way to go about this, because I need to use my nice check_malloc* function.
Additionally, in my actual text file there is a "<" symbol before the name on the first line.But I just want the *pname to point to a String saying "mynameisbob" without the "<" symbol. This isn't that important now, it just is reinforcement to me that I know I can't just set the pointer to point straight to currentline.
Can anyone help me fix my thinking on this one? Thanks a lot.
In C you need to copy chars, not the "strings" (which are just pointers). Check out strcpy() and strlen(). Use strlen() to determine how long the line actually is which fgets has read, then use your malloc() to allocate exactly that (plus 1 for the 0). Then copy the chars over with strcpy().
There are several problems in your code, see my comments in this example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Checks if malloc() succeeds.
void *check_malloc (size_t amount) {
void *tpt;
/* Allocates a memory block in amount bytes. */
tpt = malloc( amount );
/* Checks if it was successful. */
if (tpt == NULL) {
fprintf (stderr, "No memory of %lu bytes\n", amount);
exit (EXIT_FAILURE);
}
return tpt;
}
// To avoid subtle errors I have defined buffer size here
#define BUFFER_SIZE 150
// I have used the (void) version of main () here, while not strictly neccessary, you where not using argc and argv anyway, so the can be left out in this case
int main (void) {
// It might be a good idea to make the filename a char[] as well, but I leave that as an exercise to the reader.
FILE *f = fopen("abc.txt", "r"); // A file with "mynameisbob" on the first line and
// "123456789" on the second line
// You have to check whether the file was *actually openend*
if (f == NULL) {
fprintf (stderr, "Could not open file abc.txt\n"); // '"...%s\n", filename);' might better.
exit (EXIT_FAILURE);
}
char *pname; // Pointer to a string for storing the name
char currentline[BUFFER_SIZE]; // Char array for storing current line of file
while(!feof (f)) {
char *res = fgets (currentline, BUFFER_SIZE, f);
// fgets returns NULL when EOF was encountered before the next '\n'
if (res) {
size_t read = strlen (res);
// The line might have been empty
if (read) {
// Better use "sizeof *varname", while char is always 1 byte it is a good practice
pname = check_malloc ((read + 1) * sizeof *pname); // + 1 because we have to provide an extra char für '\0'
strncpy (pname, currentline, read); // You have to use strcpy or strncpy to copy the contents of the string rather than just assigning the pointer
// What was allocated must be freed again
free (pname);
}
}
}
fclose(f); // Always close everything you open!
return EXIT_SUCCESS;
}
Actually you really don't have to use pname in this simple case, because currentline already contains the line, but since you're trying to learn about memory management this should give you a general idea of how things work.
In your code you had this line:
pname = ¤tline;
There are two problems here:
As already mentioned in my code assigning currentline to pname only copies the pointer not the contents.
The correct assignment would be pname = currentline (without the address operator &), because currentline is also a pointer under the hood (it behaves like char *currentline even though it's statically allocated).
I need to read in a file. The first line of the file is the number of lines in the file and it returns an array of strings, with the last element being a NULL indicating the end of the array.
char **read_file(char *fname)
{
char **dict;
printf("Reading %s\n", fname);
FILE *d = fopen(fname, "r");
if (! d) return NULL;
// Get the number of lines in the file
//the first line in the file is the number of lines, so I have to get 0th element
char *size;
fscanf(d, "%s[^\n]", size);
int filesize = atoi(size);
// Allocate memory for the array of character pointers
dict = NULL; // Change this
// Read in the rest of the file, allocting memory for each string
// as we go.
// NULL termination. Last entry in the array should be NULL.
printf("Done\n");
return dict;
}
I put some comments because I know that's what I'm to do, but I can't seem to figure out how to put it in actual code.
To solve this problem you need to do one of two things.
Read the file as characters then convert to integers.
Read the file directly as integers.
For the first, you would use freed into a char array and then use atoi to convert to integer.
For the second, you would use fscanf and use the %d specify to read directly into an int variable;
fscanf does not allocate memory for you. Passing it a random pointer as you have will only cause trouble. (I recommend avoid fscanf).
The question code has a flaw:
char *size;
fscanf(d, "%s[^\n]", size);
Although the above may compile, it will not function as expected at runtime. The problem is that fscanf() needs the memory address of where to write the parsed value. While size is a pointer that can store a memory address, it is uninitialized, and points to no specific memory in the process' memory map.
The following may be a better replacement:
fscanf(d, " %d%*c", &filesize);
See my version of the spoiler code here
I am writing a C library. I want to return the contents of a file from this function to the caller.
How can I convert the file contents to char[]?
fopen is crashing since I am using perl.h in my C code.
Is there any other way to convert file into a char array apart from opening & reading the file?
Here is my code:
FILE* fp = fopen("console.txt", "r");
char message[1024];
strcpy(message,"\n");
char buf[80];
while(!feof(fp))
{
fgets(buf, sizeof(buf)-1, fp);
strcat(message, buf);
}
Get the file size (see How can I get a file's size in C?)
Allocate memory to store contents of the file (see malloc).
Read contents of the file into allocated memory (see read).
Return a pointer and a length of data in bytes to the user.
Don't forget to check for errors in between those steps.
You need to do a few things
Determine size of file (checkout fstat/stat)
You need to malloc enough memory to hold the file
You can then use fread to read the conents of the file into your array (dont forget to open the file in binary mode)
Return you pointer (and dont forget that it has to be freed after by the function caller)
Try this code. The function returns the string with file content, just print it.
#include <stdio.h>
#include <stdlib.h>
char *readFile(char *filename)
{
char * buffer = 0;
long length;
FILE * f = fopen (filename, "r");
if (f)
{
fseek (f, 0, SEEK_END);
length = ftell (f);
fseek (f, 0, SEEK_SET);
buffer = malloc (length);
if (buffer)
{
fread (buffer, 1, length, f);
}
fclose (f);
}
return buffer;
}
int main()
{
char *content=readFile("D://test1.xml");
printf("%s",content);
return 0;
}
Bit more information is required to give a good answer as the contents and nature of the file is required.
But generally,
If it is a text file see the stdio library - you can get the length, create an array and fill it. Otherwise (binary files) parsing it would be a good idea and return a data structure - a lot more useful
I am trying to read all content from a text file. Here is the code which I wrote.
#include <stdio.h>
#include <stdlib.h>
#define PAGE_SIZE 1024
static char *readcontent(const char *filename)
{
char *fcontent = NULL, c;
int index = 0, pagenum = 1;
FILE *fp;
fp = fopen(filename, "r");
if(fp) {
while((c = getc(fp)) != EOF) {
if(!fcontent || index == PAGE_SIZE) {
fcontent = (char*) realloc(fcontent, PAGE_SIZE * pagenum + 1);
++pagenum;
}
fcontent[index++] = c;
}
fcontent[index] = '\0';
fclose(fp);
}
return fcontent;
}
static void freecontent(char *content)
{
if(content) {
free(content);
content = NULL;
}
}
This is the usage
int main(int argc, char **argv)
{
char *content;
content = readcontent("filename.txt");
printf("File content : %s\n", content);
fflush(stdout);
freecontent(content);
return 0;
}
Since I am new to C, I wonder whether this code looks perfect? Do you see any problems/improvements?
Compiler used : GCC. But this code is expected to be cross platform.
Any help would be appreciated.
Edit
Here is the updated code with fread and ftell.
static char *readcontent(const char *filename)
{
char *fcontent = NULL;
int fsize = 0;
FILE *fp;
fp = fopen(filename, "r");
if(fp) {
fseek(fp, 0, SEEK_END);
fsize = ftell(fp);
rewind(fp);
fcontent = (char*) malloc(sizeof(char) * fsize);
fread(fcontent, 1, fsize, fp);
fclose(fp);
}
return fcontent;
}
I am wondering what will be the relative complexity of this function?
You should try look into the functions fsize (About fsize, see update below) and fread. This could be a huge performance improvement.
Use fsize to get the size of the file you are reading. Use this size to do one alloc of memory only. (About fsize, see update below. The idea of getting the size of the file and doing one alloc is still the same).
Use fread to do block reading of the file. This is much faster than single charecter reading of the file.
Something like this:
long size = fsize(fp);
fcontent = malloc(size);
fread(fcontent, 1, size, fp);
Update
Not sure that fsize is cross platform but you can use this method to get the size of the file:
fseek(fp, 0, SEEK_END);
size = ftell(fp);
fseek(fp, 0, SEEK_SET);
People often realloc to twice the existing size to get amortized constant time instead of linear. This makes the buffer no more than twice as large, which is usually okay, and you have the option of reallocating back down to the correct size after you're done.
But even better is to stat(2) for the file size and allocate once (with some extra room if the file size is volatile).
Also, why you don't either fgets(3) instead of reading character by character, or, even better, mmap(2) the entire thing (or the relevant chunk if it's too large for memory).
It is probably slower and certainly more complex than:
while((c = getc(fp)) != EOF) {
putchar(c);
}
which does the same thing as your code.
This is from a quick reading, so I might have missed a few issues.
First, a = realloc(a, ...); is wrong. If realloc() fails, it returns NULL, but doesn't free the original memory. Since you reassign to a, the original memory is lost (i.e., it is a memory leak). The right way to do this is to do: tmp = realloc(a, ...); if (tmp) a = tmp; etc.
Second, about determining the file size using fseek(fp, 0, SEEK_END);, note that this may or may not work. If the file is not random-access (such as stdin), you won't be able to go back to the beginning to read it. Also, fseek() followed by ftell() may not give a meaningful result for binary files. And for text files, it may not give you the right number of characters that can be read. There is some useful information on this topic on comp.lang.c FAQ question 19.2.
Also, in your original code, you don't set index to 0 when it equals PAGESIZE, so if your file length is greater than 2*PAGESIZE, you will overwrite the buffer.
Your freecontent() function:
static void freecontent(char *content)
{
if(content) {
free(content);
content = NULL;
}
}
is useless. It only sets a copy of content to NULL. It is just like if you wrote a function setzero like this:
void setzero(int i) { i = 0; }
A much better idea is to keep track of memory yourself and not free anything more or less than needed.
You shouldn't cast the return value of malloc() or realloc() in C, since a void * is implicitly converted to any other object pointer type in C.
Hope that helps.
One problem I can see here is variable index which is non-decreasing. So the condition
if(!fcontent || index == PAGE_SIZE) will be true only once. So I think check should be like
index%PAGE_SIZE == 0 instead of index == PAGE_SIZE.
On POSIX systems (e.g linux) you could get the same effect with the system call mmap that maps all your file in memory. It has an option to map that file copy on write, so you would overwrite your file if you change the buffer.
This would usually be much more efficient, since you leave as much as you can to the system. No need to do realloc or similar.
In particular, if you are only reading and several processes do that at the same time there would be only one copy in memory for the whole system.