Writing to a file in a C (Linux). What's wrong? - c

2 days ago I've installed linux on my machine (1st time in my life :P) and now I'm tryin to write a char into a file. For some reason, it's not working... Here's my code.
#include <stdio.h>
#include <fcntl.h>
int main (int xd, char *tab[]) {
char *path1 = tab[1];
int filee = open(path1, O_WRONLY | O_CREAT| O_TRUNC, 0777);
write(filee, 'x', sizeof(char));
close(filee);
return 0;
}
What could be wrong in this little piece of code? I've checked and function 'write' returns -1, even though function 'open' creates the file when it doesnt exist.
Thanks.

write takes a pointer to a memory buffer as the second argument, but you pass it an int
write(filee,'x',sizeof(char));
You should try something along the lines of
char c = 'x';
write(filee, &c, sizeof(char));

You are passing a character literal where write() expects a pointer to the data.
Try something like this:
const char data[] = { 'x' };
write(fille, data, sizeof data);
Also, you should check the return value of open() before relying on the file descriptor being valid.
When using API:s you're not familiar with, it's a good idea to read the manual page, and check the expected arguments against what you are using.
Also, you should enable more compiler warnings; this is something the compiler should have warned about, for sure.

Related

Calling a function doesn't execute the print statement inside that function

Why is it that my first block of code doesn't output anything while the 2nd block does print out "hi"? I suspect that the program never goes into the test() function in the first block, but I don't know why that happens and how I should fix it.
P.S. I know that my codes don't really make any sense such as that the return value of the functions should be char *. This is because I haven't completed the function and I am still at the stage of testing what I have written. I think the return value of char * shouldn't be the reason for my problem, but do let me know if it is!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* test(char **strs, int strs_sz){
printf("%s", "hi");
}
int main(void){
char *arg[] = {"XX", "YY", "ZZ"};
char *all = test(arg, 1);
printf("%s\n", all);
free(all);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* fcn(char **para){
printf("%s", "hi");
}
int main(void){
char *arg[] = {"XX", "YY", "ZZ"};
char *s = fcn(arg);
}
To sum up what was already explained in the comments and fill in some blanks:
When using standard C library functions to work with files (printf actually works with a file stdout), the data is first cached in memory, and only written to the actual file when some condition is met:
The file is closed
The file is fflushed.
The memory buffer is full
etc.
In case of stdout, this will happen when the \n character is printed or when your program exists and the file is closed.
However, in your first code snippet you try to dereference (use) a pointer all.
Since you did not write a return statement in your test function, it is impossible to predict what value will end up being stored in all.
So, your program most likely crashes unexpectedly, and thus the buffer never gets written to stdout.
You should never test incomplete functions!
At the very least, build up a skeleton code that makes the function legal, such as a dummy return statement.
Otherwise, you will encounter "undefined behavior", which is another way of saying your program will react in weird and unpredictable ways.

Fgets about the third parameter

I have this fragment
fseek(sp,f_line*fm,SEEK_SET);
fgets(buffer,LEN,(FILE*)sp);
I don't understand this part
(FILE)sp
I try to fill a char array with data from a file.
Apparently, someone thinks they are storing a file pointer in a variable sp that is not of type FILE *, so it is reputed to be necessary to cast the type to FILE *. See the POSIX definition of fgets(), which is meant to be equivalent to the standard C definition of the function.
However, given that the prior line calls fseek() with an uncast sp, and fseek() also expects a FILE *, someone is confused — the person writing the cast is confused.
The cast should be removed from the call to fgets().
Or, possibly but implausibly, the cast should be added to the call to fseek().
One outré possibility is that the user defined void *sp and used that to store the FILE * returned by fopen() or equivalent. Such a decision would be extremely unorthodox, and pointlessly opens up the code to type confusion, but could actually allow the code shown below to compile and run — but the cast is still unnecessary.
/* Abominable code - do not use! */
#include <stdio.h>
int main(void)
{
void *sp = fopen("abuse47.c", "r"); // The abomination!
if (sp != 0)
{
char buffer[256];
fseek(sp, 120, SEEK_SET);
if (fgets(buffer, sizeof(buffer), sp) != 0)
printf("[%s]\n", buffer);
fclose(sp);
}
return 0;
}

Cannot write to a .txt file using write() function in C

I wrote the following code in order to write some random characters to a text file:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
int main()
{
int input_f = open("./input.txt", O_CREAT | O_APPEND | O_RDWR ,0666);
int i;
for(i=0;i<50;i++)
{
int r = rand()%252;
printf("%d size of r: %d\n",i,sizeof(r));
write(input_f,r,sizeof(r));
printf("%d we just wrote %d which is %c\n",i,r,r);
}
close(input_f);
}
I looked for some solutions to do this
Maybe someone here knows how can I fix this?
write(input_f,r,sizeof(r));
should be
write(input_f, &r, sizeof(r));
The second parameter is the address of the buffer you want to send according to the man page.
Also you should check the return value of the function to be equal to sizeof r.
write(input_f,r,sizeof(r)); should be write(input_f,&r,sizeof(r)); because write takes a pointer to the data to be written, not the data directly.
Other then that you should be checking the result of the open call, and write calls they can fail.
You're calling write wrong.
If you'd included unistd.h, you would have gotten a prototype and the compiler would have corrected you.
write(input_f,&r,sizeof(r)); //the 2nd arg is a void const*
Also, size_t arguments to printf require "%zu", and you should be checking for errors.
Others have already said why it doesn't work
I just want to add that you should also write :
#include <unistd.h>
Or else you'll get warnings during compilation.
The write() function do not take an int as second parameter but a pointer (void *) on a buffer, and its length. It means you will have to convert your int into a string in a buffer first (with sprintf() for instance) and then output the buffer to the file (with write())

variadic function- reading files (c)

i need to create a variadic function (stdarg library) which will loop through all the files i pass it and will count words similiar to a word i pass as a parameter,
#include <stdio.h>
#include <stdarg.h>
void countWords(char* name, FILE* file, ...){
va_list params;
FILE* currentFile;
FILE* f;
int words = 0;
va_start(params, file);
currentFile = file;
while (currentFile != NULL)
{
f = fopen(currentFile, "r+"); //which file should i open every time? this doesnt compile
// comparing words in each file code
currentFile = va_arg(params, FILE*);
}
va_end(params);
}
i cant read the file (no metter what i try it doesnt compile),
and how can i loop through each file comparing my word? i would really appreciate guidance
thank you!
If you are passing the file name or more precisely the path to the file, then this
FILE *currentFile;
currentFile = va_arg(params, FILE *);
should be
char *currentFile;
currentFile = va_arg(params, char *);
If you pass FILE pointers, you should not open them because if the rest of the program is correct then they shall be already opened inside the funcion, otherwise it doesn't make any sense to pass FILE *'s.
So the function should probably be
#include <stdio.h>
#include <stdarg.h>
void countWords(char *word, char *filename, ...)
{
va_list params;
FILE *file;
int words;
words = 0;
va_start(params, file);
while (filename != NULL)
{
file = fopen(filename, "r+");
// comparing words in each file code
filename = va_arg(params, char *);
}
va_end(params);
}
You would call it like this
countWords("example", "/path/to/file/1", ..., "/path/to/file/n", NULL);
and you should be careful with string literals probably use the const qualifier in this situation, because even if the parameters are not string literals it wouldn't make sense to modify them inside countWords() so to prevent accidentally modifying them const could help, although you can always modify them anyway. Even if modifying a string literal invokes undefined behavior you cannot completely forbid your program from doing so.
i need to create a variadic function
Unless this is a homework assignment about variadic functions, you don't need a variadic function at all. Variadic functions are not type safe and type safety is a desirable property.
Others have already pointed this out: You need a function that takes a filename and counts the occurrences of a word in a single file
size_t occurrences(const char *word, const char *filename) { ... }
You can then easily loop over an array of files, e.g.:
size_t count = 0;
for (int i = 1, i < argc; i++) {
size += occurrence("pink", argv[i]);
}
If you like, you can wrap this in a separate function which takes an array of file names with a file count. This is easily done, because whether you take your files from a command line or from somewhere else, you already have them stored in some kind of array.
Now consider the variadic variant, which makes sense only if you know the files you want to process at compile time, e.g.:
size_t n = var_occurrences("banana",
"alpha.txt", "beta.txt", "gamma.txt", NULL);
The same can be achieved with the non-variadic approach:
const char *w = "banana";
size_t n = occurrences(w, "alpha.txt")
+ occurrences(w, "beta.txt")
+ occurrences(w, "gamma.txt");
This is a bit more typing, but everything else is much more straightforward. If you must use variadic functions, go ahead and look at iharob's answer. But variadic functions are not a good solution to your task.

Weird segfault after open file?

I'm getting a seg fault when I try and print fname. Can someone explain why this is happening to me? Is it that I'm not allowed to write to a file, close it, and then read from a file? argv[2] is defined. I've tried with multiple different allocations.
int main(int argc, char *argv[]){
//Other stuff
char *rfile=calloc(1, 2049);
strcpy(rfile, argv[2]);
FILE *wfile;
wfile = fopen(argv[2], "w");
SaveIndexToFile(index, wfile, alpha); // This does a whole bunch of writing to a the file.
fclose(wfile);
//alpha is declared here, and works just fine.
RemakeIndex(rfile, alpha);
return 1;
}
int RemakeIndex(char *fname, WordList * alpha){
printf("%s", fname);
return 1;
}
You are not checking the return value of fopen. If the fopen fails it can
return NULL. If you are doing something with NULL that can undefined behavior. Place this line after opening the file.
if ( wfile == NULL ){
perror("fopen");
return;
}
And check whether the argc count is three. If you are not giving arguments to the ./a.out then accessing the argv[2] can also lead to segmentation fault.
Is it that I'm not allowed to write to a file, close it, and then read from a file?
Yes, you are not allowed to read from a file [stream] after it had been closed.
Note on the (OP's) wording:
char * rfile is called a "pointer to char".
FILE * is called a "file-pointer" (or also just "pointer to FILE) or commonly (but formally wrong) just "file".
Also RemakeIndex() is called in main() without proper protoyping.
To fix this
either add a prototype before main():
int RemakeIndex(char *, WordList *);
or move the whole implementation of RemakeIndex() before main().
Also the printf() calls' output might not show up immediately on the console, as stdout is line buffered.
To fix this
either print out a trailing new-line:
printf("%s\n", fname);
or printf to stderr, which itself isn't line bufferd by default:
fprintf(strerr, "%s\n", fname);
or flush stdout after having printed to it:
printf("%s\n", fname);
fflush(stdout);
Prototyping the function is very important, the GCC compiler will assume an implicitly declared function (RemakeIndex in your code) has two arguments which are both int, which would make your code look like this:
int RemakeIndex(int fname, int alpha) {
printf("%s", (char *)fname);
return 1;
}
On a 64 bit machine and with GCC where pointers are 64 bits and ints are 32 bits then your arguments will be truncated to 32 bits which is likely to cause a segfault. The other answers have mentioned prototyping the function and if you are using a 64bit compiler I would suggest that this is your problem.
It ended up being that I was allocating way too much memory on the heap. I had a loop that was allocating strings of max_length of an unsigned int. Thank you for all of your comments and help!

Resources