How to use the "write" system call using C langauge in Linux? - c

My code is working fine. The only error I'm getting is that after the program writes the text into the file i.e. text1.txt, the text file prints some weird symbols like /00 when I actually open it.
int fd;
fd = open("text1.txt", O_RDWR);
char text[] = "This is my file.";
write(fd,text,sizeof(text));

You need to ensure that open succeeded instead of blindly writing to the file-descriptor.
Always check the return value of a syscall (and most C standard library functions) and check errno if the return value indicated an error.
Your string literal will include a hidden \0 (NULL) character after the dot.
Writing text directly to the file will therefore include the trailing \0 which is what you're seeing.
These issues can be rectified by:
Always checking the return value of a syscall - and in this case: print a helpful error message to stdout and perform any necessary cleanup (the goto closeFile; statement).
Because C doesn't have a native try/catch or RAII it means its difficult to write terse error-handling and cleanup code, but using goto for common clean-up code is generally acceptable in C, hence the goto closeFile statement.
Using strlen to get the actual length of the string.
Though in a pinch it's okay to use sizeof(text) - 1 provided you're in a scope where the C compiler knows the length of text as using sizeof() won't work if you cross a function boundary due to array pointer decay.
Like so:
void writeToFile() {
int fd = open( "text1.txt", O_CREAT | O_WRONLY ); // Use `O_WRONLY` instead of `O_RDWR` if you're only writing to the file. Use `O_CREAT` to create a file if it doesn't already exist.
if( fd == -1 ) {
printf( "Error opening file: errno: %d - %s\n", errno, strerror( errno ) );
return;
}
size_t textLength = strlen( text );
size_t written = write( fd, text, textLength );
if( written == -1 ) {
printf( "Error writing text: errno: %d - %s\n", errno, strerror( errno ) );
goto closeFile;
}
else if( written < textLength ) {
printf( "Warning: Only %d of %d bytes were written.", written, textLength );
goto closeFile;
}
else {
// Carry on as normal.
}
closeFile:
if( close( fd ) == -1 ) {
printf( "Error closing file: errno: %d - %s\n", errno, strerror( errno ) );
}
}

Related

getting undefined behavior in counting characters of text file program?

I wrote a c program meant to count the characters in a certain file.
int main(void) {
FILE *fp;
fp = fopen("txt.txt", "r");
char text;
int count;
while (fscanf(fp, "%c", &text) != EOF) {
count++;
}
printf("%d", count);
return 0;
}
I want to add a char array into it but for some reason it changes the value of my int type (count).
for example, if I run this program I get an output of 3549. Now, lets say I declare "char potato[5000]" alongside my other char type. For some reason I get a completely different output of 159062601. Why is this and how do I prevent that?
The following proposed code:
initializes variables before using them (your compiler should have told you about this problem.
properly checks and handles I/O errors for fopen() and for fscanf()
properly closes the open file before exiting. I.E. it cleans up after itself
properly terminates printed text, so it is immediately passed to the terminal
and now, the proposed code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
FILE *fp;
fp = fopen("txt.txt", "r");
if( ! fp )
{
perror( "fopen failed" );
exit( EXIT_FAILURE );
}
char text;
int count = 0;
while ( fscanf( fp, "%c", &text ) == 1 )
{
count++;
}
fclose( fp );
printf( "%d\n", count );
return 0;
}
You have several problems in your code. i will list them below:
In c programming we declare variables in the scope begin. and initialize them if we need so. you have a mixture of declerations and code.
count variable non initialized!! you have entered the while loop with garbage value in count. UB (Undefined behavior) - in each run you will get different values.
you didnt check the return value of fopen !! you must check if the operating system succed in opening the file you have requested to manipulate.
regarding asking a question in stackoverflow, your code is not complete and you didnt post all of it.
Now lets try to learn new topics regarding working with IO streams.
return value of function fscanf
The value EOF is returned if the end of input is reached before
either the first successful conversion or a matching failure occurs.
EOF is also returned if a read error occurs, in which case the
error indicator for the stream (see ferror(3)) is set, and errno
is set indicate the error.
This is how check if errors ocured while working with the file we are reading:
int ferror(FILE *stream);
The function ferror() tests the error indicator for the stream pointed
to by stream, returning nonzero if it is set. The error indicator can
only be reset by the clearerr() function.
And in this function bellow we get a human readble error, not just an errnor number!
explain_ferror
const char *explain_ferror(FILE *fp);
The explain_ferror function is used to obtain an explanation of an
error returned by the ferror(3) system call. The least the message
will contain is the value of strerror(errno), but usually it will do
much better, and indicate the underlying cause in more detail.
The errno global variable will be used to obtain the error value to be
decoded.
#include <stdlib.h>
#include <stdio.h>
#include <libexplain/ferror.h> /* for the non standard const char* explain_ferror(FILE* fp); */
int main(void)
{
FILE *fp;
char text;
int count = 0;
fp = fopen("txt.txt", "r");
if(fp == NULL)
{
perror("fopen failed"); /*write to standard error*/
exit(EXIT_FAILURE);
}
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", explain_ferror(fp));
exit(EXIT_FAILURE);
}
printf("%d", count);
return 0;
}
Since the const char *explain_ferror(FILE *fp); is not GNU standard function, i am posting a GNU standard functions in the code snippet below:
char *strerror(int errnum);
strerror is standard library c function which returns a pointer to a string that describes the error code passed in the argument errnum. Be aware that this function is not Thread safe. for thread safe function use The strerror_r().
Return Value
The strerror(), function return the appropriate error description string, or an "Unknown error nnn" message if the error number is unknown.
Since POSIX.1-2001 and POSIX.1-2008 requires that a successful call to strerror() shall leave errno unchanged, and note that, since no function return value is reserved to indicate an error, if we wishe to check for errors we should initialize errno to zero before the call (by calling void clearerr(FILE *stream);, and then check errno after the call.
#include <string.h>
#include <errno.h>
#include <stdio.h>
...
clearerr(fp); /* clear previous seted errno */
while (fscanf(fp, "%c", &text) != EOF)
{
++count;
}
if (ferror(fp)) /* nonzero return if error occured */
{
fprintf(stderr, "%s\n", strerror(errno));
exit(EXIT_FAILURE);
}
...
Finally:
man pages (or man7) or typing man <enter_string_here> in terminal on linux shall clear all the q.marks.
for further reading go to:
explain_ferror
ferror
fscanf

Read from file a number and after that an array in C

How can I read from a file a number and after an array. i mean my file looks like that:
3
7
8
9
3 is the number of components, 7, 8 9 the other components of the array, arr[1], arr[2], arr[3].
one way to perform the desired functionality is:
First, open the file for reading:
FILE *fp = fopen( "filename.txt" );
Then check that the call to fopen() was successful and handle any error:
if( ! fp )
{
perror( "fopen to read filename.txt failed" );
exit( EXIT_FAILURE );
}
Note: perror() outputs both your error message and the text reason the system thinks the error occurred to stderr. which is where error messages should be output.
reserve a variable to hold the count of following values:
int maxLoops;
then read the first number and use that number as the max iterations of a loop, of course, checking for errors
if( fscanf( fp, "%d", &maxLoops ) != 1 )
{
fprintf( stderr, "fscanf to read loop count failed\n" );
exit( EXIT_FAILURE );
}
Note: the scanf() family of functions does not set errno when some input format specifier (in this case %d) fails, so need to output an error message using something like fprinf().
Note: the scanf() family of functions returns the number of successful input format conversions (or EOF)
Note: exit() and EXIT_FAILURE are exposed via:
#include <stdlib.h>
then, reserve an array for the following entries in the file, using the Variable Array Length feature of C
int dataArray[ maxLoops ];
Now, set up the loop that will read the rest of the data
for( int i = 0; i < maxLoops; i++ )
{
for each pass through the loop read another entry into the array, of course, checking for errors
if( fscanf( fp, "%d", &dataArray[i] ) != 1 )
{
fprintf( stderr, "fscanf for data value failed\n" );
exit( EXIT_FAILURE );
}
} // end the loop
then, cleanup before doing anything else:
fclose( fp );
What you do with the data is up to you. You might want to print out each of the data values with a loop, similar to:
for( int i = 0; i < maxLoops; i++ )
{
printf( "entry %d = %d\n", i, dataArray[i] );
}
Note: when calling printf() no need to obtain the address of a variable (unless that is what you want to print). However, when inputting a variable, as when calling fscanf() need the address of the variable.

how to print first 10 lines of a text file using Unix system calls?

I want to write my own version of the head Unix command, but my program is not working.
I am trying to to print the first 10 lines of a text file, but instead the program prints all the lines. I specify the file name and number of lines to print via command-line arguments. I am only required to use Unix system calls such as read(), open() and close().
Here is the code:
#include "stdlib.h"
#include "stdio.h"
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#define BUFFERSZ 256
#define LINES 10
void fileError( char*, char* );
int main( int ac, char* args[] )
{
char buffer[BUFFERSZ];
int linesToRead = LINES;
int in_fd, rd_chars;
// check for invalid argument count
if ( ac < 2 || ac > 3 )
{
printf( "usage: head FILE [n]\n" );
exit(1);
}
// check for n
if ( ac == 3 )
linesToRead = atoi( args[2] );
// attempt to open the file
if ( ( in_fd = open( args[1], O_RDONLY ) ) == -1 )
fileError( "Cannot open ", args[1] );
int lineCount = 0;
//count no. of lines inside file
while (read( in_fd, buffer, 1 ) == 1)
{
if ( *buffer == '\n' )
{
lineCount++;
}
}
lineCount = lineCount+1;
printf("Linecount: %i\n", lineCount);
int Starting = 0, xline = 0;
// xline = totallines - requiredlines
xline = lineCount - linesToRead;
printf("xline: %i \n\n",xline);
if ( xline < 0 )
xline = 0;
// count for no. of line to print
int printStop = lineCount - xline;
printf("printstop: %i \n\n",printStop);
if ( ( in_fd = open( args[1], O_RDONLY ) ) == -1 )
fileError( "Cannot open ", args[1] );
//read and print till required number
while (Starting != printStop) {
read( in_fd, buffer, BUFFERSZ );
Starting++; //increment starting
}
//read( in_fd, buffer, BUFFERSZ );
printf("%s \n", buffer);
if ( close( in_fd ) == -1 )
fileError( "Error closing files", "" );
return 0;
}
void fileError( char* s1, char* s2 )
{
fprintf( stderr, "Error: %s ", s1 );
perror( s2 );
exit( 1 );
}
What am I doing wrong?
It's very odd that you open the file and scan it to count the total number lines before going on to echoing the first lines. There is absolutely no need to know in advance how many lines there are altogether before you start echoing lines, and it does nothing useful for you. If you're going to do it, anyway, however, then you ought to close() the file before you re-open it. For your simple program, this is a matter of good form, not of correct function -- the misbehavior you observe is unrelated to that.
There are several problems in the key portion of your program:
//read and print till required number
while (Starting != printStop) {
read( in_fd, buffer, BUFFERSZ );
Starting++; //increment starting
}
//read( in_fd, buffer, BUFFERSZ );
printf("%s \n", buffer);
You do not check the return value of your read() call in this section. You must check it, because it tells you not only whether there was an error / end-of-file, but also how many bytes were actually read. You are not guaranteed to fill the buffer on any call, and only in this way can you know which elements of the buffer afterward contain valid data. (Pre-counting lines does nothing for you in this regard.)
You are performing raw read()s, and apparently assuming that each one will read exactly one line. That assumption is invalid. read() does not give any special treatment to line terminators, so you are likely to have reads that span multiple lines, and reads that read only partial lines (and maybe both in the same read). You therefore cannot count lines by counting read() calls. Instead, you must scan the valid characters in the read buffer and count the newlines among them.
You do not actually print anything inside your read loop. Instead, you wait until you've done all your reading, then print everything the buffer after the last read. That's not going to serve your purpose when you don't get all the lines you need in the first read, because each subsequent successful read will clobber the data from the preceding one.
You pass the buffer to printf() as if it were a null-terminated string, but you do nothing to ensure that it is, in fact, terminated. read() does not do that for you.
I have trouble believing your claim that your program always prints all the line of the designated file, but I can believe that it prints all the lines of the specific file you're testing it on. It might do that if the file is short enough that the whole thing fits into your buffer. Your program then might read the whole thing into the buffer on the first read() call (though it is not guaranteed to do so), and then read nothing on each subsequent call, returning -1 and leaving the buffer unchanged. When you finally print the buffer, it still contains the whole contents of the file.

Error checking and the added length thereof - is there an analog to interrupts from embedded system programming?

Of course it is necessary to check whether certain operations occurred as expected: calls to malloc, fopen, fgetc
However, sometimes adding these checks makes the code way too long - especially for very simply functions. For example, I have a function where I must open a file, read in a few parameters, and allocate memory corresponding to what was just read in.
Therefore, the code ends up looking something like:
Open file
Check if file opened
Read parameter
Check if file EOF was not read (if it was, file format is incorrect)
Allocate memory
Check if memory allocation occurred as expected
Etc.
There appears to be quite a bit of redundancy here. At least for my simple program, if any of the above checks file, I simply report the error and return control to the operating system. The code ends up looking something like this:
if(filePointer == NULL){
perror("Error X occured");
exit(EXIT_FAILURE);
}
So, a simple few-line function turns into perhaps 20 or more lines because of this error checking. Is there some where to aggregate the determination of these errors?
Just wondering if there was something that I missed.
EDIT: For example, is there a way to interrupt the flow of program when certain events occur? I.e. if EOF is read prematurely, then jump to some function that informs the user (something like an interrupt in embedded systems).
This is a question that every C programmer asks at some point in his/her career. You are correct that some portions of your code will have more lines of error handling code than actual useful productive code. One technique I've used in the past to streamline error handling is to implement an error function, like this
static FILE *fpin = NULL;
static FILE *fpout = NULL;
static BYTE *buffer = NULL;
static void error( char *msg, char *name )
{
if ( msg != NULL )
{
if ( name != NULL )
fprintf( stderr, "%s: %s\n", msg, name );
else
fprintf( stderr, "%s\n", msg );
}
if ( fpin != NULL )
fclose( fpin );
if ( fpout != NULL )
fclose( fpout );
if ( buffer != NULL )
free( buffer );
exit( 1 );
}
which then gets used like this
void main( int argc, char *argv[] )
{
if ( argc != 3 )
error( "Usage: ChangeBmp infile outfile" );
if ( (fpin = fopen( argv[1], "rb" )) == NULL )
error( "Unable to open input file", argv[1] );
if ( (fpout = fopen( argv[2], "wb" )) == NULL )
error( "Unable to open output file", argv[2] );
size = sizeof( bmphead );
if ( fread( &bmphead, 1, size, fpin ) != size )
error( "Unable to read header", NULL );
size = sizeof( bmpinfo );
if ( fread( &bmpinfo, 1, size, fpin ) != size )
error( "Unable to read info", NULL );
Of course, this only works if the error function has access to all of the necessary variables. For simple, single file programs, I just make the necessary variables global. In a larger project, you might have to manage the variables more carefully.
One common way to address this, at least to reduce apparent code size, is wrapping the various checks with macros: e.g.,
#define CHECK_NULL(expr) { \
if ((expr) == NULL) { \
perror("Error X"); \
exit(-1); \
} \
}
CHECK_NULL(p = malloc(size))
CHECK_NULL(filePointer = fopen("foo.txt", "r"))
As for interrupting control flow, other languages often use exceptions, which are also possible in C. However, this tends to be platform-specific and isn't usually the way it's done in practice with C.

Check to see if a file exists before writing to it and then ask to overwrite in C with POSIX

Ok, I have a homework assignment to write a file in C using the POSIX API that asks for a filename to read from, a filename to write to and then copies one to the other. I have done this and it works great! I am trying to put some error checking in and I want to check to see if the file to be written to already exists and if it does, then ask if the user wishes to overwrite. The problem is that it always states that the file exists, even if it does not. The rest of the program works just fine. I have read a lot on here and found a lot of useful stuff on POSIX, but can't find this type of problem to reference. Below is my code:
#include <fcntl.h> // POSIX: give access to open
#include <unistd.h> // POSIX: gives access to read, write, close
#include <stdio.h> // POSIX: gives access to BUFSIZ
int main() {
int source = -1;
int target;
char sourcefile[50];
char targetfile[50];
char buff[BUFSIZ];
char ow[3];
size_t size;
printf("Please enter the name of the file you wish to read: ");
scanf( "%s", sourcefile );
printf( "\n" );
printf("Please enter the name of the file you wish to write to: ");
scanf( "%s", targetfile );
printf( "\n" );
source = open( sourcefile, O_RDONLY, 0);
//Test for existence of input file
if( source == -1 )
{
perror( "Cannot find file" );
return 1;
}
target = open( targetfile, O_WRONLY, 0644 );
//Test for existence of output file
if( target == 0 )
{
perror( "File already exists" );
printf( "Do you wish to overwrite? (yes or no): " );
scanf( "%s", ow );
if( strcmp( ow, "yes" ) == 0 )
{
target = open( targetfile, O_WRONLY | O_CREAT, 0644);
}else
{
printf( "Program Terminated!\n" );
return 1;
}
}else if( target == -1 )
{
target = open( targetfile, O_WRONLY | O_CREAT, 0644);
}
while ((size = read(source, buff, BUFSIZ)) > 0)
{
write(target, buff, size);
}
close(source);
close(target);
return 0;
}
You can use open(2) with O_EXCL to create the purported new file. This will fail if the file already exists; in that case abort fatally. Otherwise you can write the desired file contents into it.
If you want to be atomic, you can write the file contents into a temporary file (using tmpfile) and then atomically replace the created file with rename(2). That way the new file is either empty or a complete copy.
An alternative (suggested by #R.) is to not bother opening the target file, copying into a temporary file, and then using link(2) instead of rename to attempt to put the new file in its destination location. This will fail if the destination already exists. This may have the (arguable) benefit that if someone else creates the target file in the meantime and doesn't use the same care that we do, then you would be a bit more gentle in that case. (But if someone else wants stampedes around your filesystem without care, there's only so much you can do.)

Resources