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
Related
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
I have a function that receives the name of a file as an argument.
The idea is to read each word in the given file and save each one in a linked list (as a struct with a value and a pointer to the next struct).
I could get it working for small files, but when I give a big .txt file I get a segmentation fault.
Using gdb I could figure out that this happens at the while(fscanf(fi, "%s", value) != EOF){ line.
For some reason when the file is bigger the fscanf() segfaults.
As I could figure out the linked list part, here I pasted just enough code to compile and for you to see my problem.
So my question are:
Why fscanf() segfauts with big .txt files (thousands of words), but not with small file (ten words)?
By the way, is there a better way to check for the end of the file?
Thanks in advance.
bool read(const char* file){
// open file
FILE* fi = fopen(file, "r"); //file is a variable that contains the name of the file to be opened
if (fi == NULL)
{
return false;
}
// malloc for value
char* value = malloc(sizeof(int));
// fscanf() until the end of the file
while(fscanf(fi, "%s", value) != EOF){ // HERE IS MY PROBLEM
// some code for the linked list
// where the value will be saved at the linked list
}
// free space
free(value);
// close the file
fclose(fi);
return true;
}
No, here is your problem:
char* value = malloc(sizeof(int)); // <<<<<<< You allocate only place for an int
while(fscanf(fi, "%s", value) != EOF){ // <<<<<<< but you read a huge string
So you end up with a buffer overflow !
You have to make sure that you never overflow the size of your buffer by setting some limits. For example by using the width field of fscanf() to indicate max size of chars to be read for the string:
char* value = malloc(512); // Allocate your buffer
while(fscanf(fi, "%511s", value) != EOF){ // read max 511 chars + 1 char for terminating 0
...
(disclaimer: simplified explanation)
A char* is a pointer to an address of memory. It specifies that it points to an array of characters. A malloc call reserves a block of memory of a certain size.
Your line
char* value = malloc(sizeof(int));
creates a character array that can hold 4 characters (as an int is 4 bytes long generally). And for it to be a complete string the last character has to be a NULL terminator '\0', So really it can only hold 3 readable characters.
You should make that malloc create a block of memory that is larger than the biggest string in the file. Or you could use another safer method such as fgets : http://www.cplusplus.com/reference/cstdio/fgets/
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 have a text file called "graphics" which contains the words "deoxyribonucleic acid".
When I run this code it works and it returns the first character. "d"
int main(){
FILE *fileptr;
fileptr = fopen("graphics.txt", "r");
char name;
if(fileptr != NULL){ printf("hey \n"); }
else{ printf("Error"); }
fscanf( fileptr, "%c", &name);
printf("%c\n", name);
fclose( fileptr );
return 0;
}
When I am using the fscanf function the parameters I am sending are the name of the FILE object, the type of data the function will read, and the name of the object it is going to store said data, correct? Also, why is it that I have to put an & in front of name in fscanf but not in printf?
Now, I want to have the program read the file and grab the first word and store it in name.
I understand that this will have to be a string (An array of characters).
So what I did was this:
I made name into an array of characters that can store 20 elements.
char name[20];
And changed the parameters in fscanf and printf to this, respectively:
fscanf( fileptr, "%s", name);
printf("%s\n", name);
Doing so produces no errors from the compiler but the program crashes and I don't understand why. I am letting fscanf know that I want it to read a string and I am also letting printf know that it will output a string. Where did I go wrong? How would I accomplish said task?
This is a very common problem. fscanf reads data and copies it into a location you provide; so first of all, you need the & because you provide the address of the variable (not the value) - that way fscanf knows where to copy TO.
But you really want to use functions that copy "only as many characters as I have space". This is for example fgets(), which includes a "max byte count" parameter:
char * fgets ( char * str, int num, FILE * stream );
Now, if you know that you only allocated 20 bytes to str, you can prevent reading more than 20 bytes and overwriting other memory.
Very important concept!
A couple of other points. A variable declaration like
char myString[20];
results in myString being a pointer to 20 bytes of memory where you can put a string (remember to leave space for the terminating '\0'!). So you can usemyStringas thechar *argument infscanforfgets`. But when you try to read a single character, and that characters was declared as
char myChar;
You must create the pointer to the memory location "manually", which is why you end up with &myChar.
Note - if you want to read up to white space, fscanf is the better function to use; but it will be a problem if you don't make sure you have the right amount of space allocated. As was suggested in a comment, you could do something like this:
char myBuffer[20];
int count = fscanf(fileptr, "%19s ", myBuffer);
if(count != 1) {
printf("failed to read a string - maybe the name is too long?\n");
}
Here you are using the return value of fscanf (the number of arguments correctly converted). You are expecting to convert exactly one; if that doesn't work, it will print the message (and obviously you will want to do more than print a message…)
Not answer of your question but;
for more efficient memory usage use malloc instead of a static declaration.
char *myName // declara as pointer
myName = malloc(20) // same as char[20] above on your example, but it is dynamic allocation
... // do your stuff
free(myName) // lastly free up your allocated memory for myName