Unix and Advance Topics in C Programming: A Simple C Program
Unix and Advance Topics in C Programming: A Simple C Program
PROGRAMMING
Objectives
A SIMPLE C PROGRAM
Example#1:
#include <stdio.h> is a directive to the c preprocessor to include the file stdio.h that will
tell the program how to input and output data.
#include <stdlib.h> is to be able to use the exit function that tells us if the program ran
successfully or not.
The ’-o’ option indicates that the compile file should be stored in a file called ’FileName’
instead of the default ’a.out’.
Con’t Example#1:
59 | P a g e
> ./a.out
Or you can compile the program in example #1 using –o option
gcc -o file file.c
Run the program
> ./file
The UNIX system provides a large number of C functions as libraries. Some of these implement
frequently used operations, while others are very specialized in their application. Do Not
Reinvent Wheels: It is wise for programmers to check whether a library function is available to
perform a task before writing their own version. This will reduce program development time.
The library functions have been tested, so they are more likely to be correct than any function
which the programmer might write. This will save time when debugging the program.
The UNIX manual has an entry for all available functions. Function documentation is stored in
section 3 of the manual, and there are many other useful system calls in section 2. If you already
know the name of the function you want, you can read the page by typing (to find about sqrt):
man 3 sqrt
If you don’t know the name of the function, a full list is included in the introductory page for
section 3 of the manual. To read this, type
man 3 intro
There are approximately 700 functions described here. This number tends to increase with each
upgrade of the system.
Example#2
The file sqrt1.c contains c code prints the square roots of the numbers from 0 to 25.
Notice that we converted the integer i to a double using the typcast operation.
#include <stdio.h>
#include <math.h>
int main()
{
int i;
double number;
for (i = 0; i <= 25; i++) {
number = sqrt((double) i);
printf(“The square root of %d is %f\n”,i,number);
}
}
60 | P a g e
To compile program that used c library: gcc -o sqrt1 sqrt1.c -lm
This example generates random numbers that range from a minimum value of 3 and a
maximum value of 12. Notice that we used the modulo operator % to ensure maximum
value of our random numbers is less than 10.
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i, number, min value;
min value = 3;
for (i = 0; i < 15; i++)
{
number = min value + (rand() % 10);
printf(”Random number is %d \”);
}
}
C FUNCTIONS
C uses “function” to package blocks of code. A function has a name, a list of arguments and the
block of code it executes.
Example #4:
The following example shows a function that converts speed from miles/hour to
kilometers/hour.
#include <stdio.h>
float mphtokph(float speed)
{
return(speed*1.60934);
}
int main()
{
float mph, kph;
printf("Enter speed (miles/hour): ");
scanf("%f", &mph);
kph = mphtokph(mph);
61 | P a g e
printf("\n speed of %3.1f miles/hour equals %3.1f
kilometers/hour \n\n",mph, kph);
}
The arguments for main( int argc, char *argv[] ) are argc(argument count) and argv(argument
vector). The argument argc is an integer that contains the number of arguments being passed to main ;
argv is an array of strings. Each string is an argument. The computer is able to count the number of
arguments and assign the value to argc. The array argv[1] contains the first argument, argv[2]
contains the second argument and so on . The program’s name is stored in argv[0].
Example#5:
For a program named prog1 which is invoked with the command line: The value of argc is
4, the value of argv[0] is "prog1", the value of argv[1] is "add", the value of argv[2] is
"12", and the value of argv[3] is "5".
>prog1 add 12 5
Example#6:
Try to run the program with and without argument and see the result.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
int i;
for (i = 0; i < argc ; i++) // scan al entries of argv[i]
{
/* print all the arguments */
printf(“arg %d: %s \n”, i, argv[i]);
}
exit (0);
}
Example#7:
62 | P a g e
printf("You must input three numbers as command line inputs.\n");
exit(0);
}
sum=atoi(argv[1])+atoi(argv[2])+atoi(argv[3]);
printf("The sum of three values is = %d\n",sum);
}
We can run commands from a C program just as if they were from the UNIX command line by
using the system( ) function.
int system ( char *string ) where string can be the name of a UNIX utility, an executable shell
script or a user program. System returns the exit status of the shell.
system is a call that is made up of 3 other system calls: execl( ), wait( ) and fork( ) (which are
prototyped in <unistd>)
Example#8:
63 | P a g e
LABORATORY8: MAJOR FILE STRUCTURE RELATED SYSTEM CALLS
Objective
A system call is a request for the operating system to do something on behalf of the user's
program. The system calls are functions used in the kernel itself. To the programmer, the
system call appears as a normal C function call. However since a system call executes code in
the kernel, there must be a mechanism to change the mode of a process from user mode to
kernel mode.
1. The UNIX system interface consists of about 80 system calls (as UNIX evolves
this number will increase). The table below lists about 40 of the most important
system call.
2. The file structure related system calls in UNIX let you create, open, and close
files, read and write files, randomly access files, alias and remove files, get
information about files, check the accessibility of files, change protections,
owner, and group of files, and control devices.
64 | P a g e
65 | P a g e
System call operations either use a character string that defines the absolute or relative
path name of a file, or a small integer called a file descriptor that identifies the I/O
channel.
A channel is a connection between a process and a file that appears to the process as an
unformatted stream of bytes.
File descriptors 0, 1, and 2 refer to standard input, standard output, and standard error
files respectively.
File descriptor 0 is a channel to your terminal's keyboard and file descriptors 1 and 2
are channels to your terminal's
The mode is usually specified as an octal number such as 0666 that would mean read/write
permission for owner, group, and others or the mode may also be entered using manifest
constants defined in the "/usr/include/sys/stat.h" file. e.g. S_IREAD,S_IWRITE
Header files needed for this system call in which the actual prototype appears, & in which
useful constants are defined are:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
All input and output operations start by opening a file using either the "creat( )" or "open( )"
system calls. These calls return a file descriptor that identifies the I/O channel. Recall that
file descriptors 0, 1, and 2 refer to standard input, standard output, and standard error files
respectively, and that file descriptor 0 is a channel to your terminal's keyboard and file
descriptors 1 and 2 are channels to your terminal's display screen.
Example#1:
Create a file newfile with read & write permission to owner and read only for the group
and others.
fd = creat(“/tmp/newfile”, 0644);
66 | P a g e
Example#2:
After running the example check whether, the file datafile.dat exist in your current folder
or not.
#include <stdio.h>
#include <sys/types.h> /* defines types used by sys/stat.h */
#include <sys/stat.h> /* defines S_IREAD & S_IWRITE */
int main( )
{
int fd;
fd = creat("datafile.dat", S_IREAD | S_IWRITE);
if (fd == -1)
printf("Error in creating datafile.dat\n");
else
{
printf("datafile.dat created for read/write access\n");
printf("datafile.dat is currently empty\n"); }
close(fd);
exit (0); /*exit() terminates the calling process , exit(0) for successful &
exit(1) for error, exit() is defined in #include<stdlib.h> */
}
mode defines the file's access permissions if the file is being created. It is only
used with the O_CREAT option_flag and it is concerned with the security
permissions.
Header files needed for this system call in which the actual prototype appears, & in
which useful constants are defined are:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
67 | P a g e
The allowable option flags as defined in "/usr/include/fcntl.h" or #include<fcntl.h> are:
Option flag Description
#define O_RDWR 2 Open the file for both reading and writing
#define O_CREAT 00400 If file doesn’t exist , create the file, set the owner ID to the process’s
effective UID, and set the group id to the group id of the directory in
which the file is created.
#define O_EXCL 02000 Exclusive open(i. e If O_CREAT is set and the file exists, then open() fails.
Multiple values are combined using the | operator (i.e. bitwise OR). Note: some combinations
are mutually exclusive such as: O_RDONLY | O_WRONLY and will cause open( ) to fail. If the
O_CREAT flag is used, then a mode argument is required. The mode argument may be
specified in the same manner as in the creat( ) system call.
Example#3:
This causes the file data, in the current working directory, to be opened as read only for the
use by the program.
fd = open(“data”, O_RDONLY);
Example#4:
The open call can also be used to create a file from scratch, as follows:
fd = open (“/tmp/newfile”, O_WRONLY | O_CREAT, 0644);
Example#5:
means, if file lock does not exist, then create it with permission 0644. If it does exist, then
fail open call, returning –1 in fd.
fd = open(“lock”, O_WRONLY | O_CREAT | O_EXCL, 0644);
Example#6:
O_TRUNC when used with O_CREAT it will force a file to be truncated to zero bytes if it
exists and its access permissions allow.
fd = open(“file”, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Example#7:
#include<stdlib.h>
68 | P a g e
#include<fcntl.h>
#define PERMS 0644 /* Permission for open with O_CREAT */
char *filename = "newfile";
main()
{
int fd;
if((fd=open(filename, O_RDWR | O_CREAT, PERMS)) == -1)
{
printf("Couldn't create %s\n",filename);
exit(1); /*error, so exit */
}
printf(“The file is opened and ready for read and write operation“)
/* rest of program follows */
exit(0); /*normal successful exit */
}
transfer_size defines the maximum number of characters transferred between the file
and the buffer (or number of bytes) . There is no limit on transfer_size, but you must
make sure it's safe to copy transfer_size bytes to or from the memory pointed to by
buffer_pointer. A transfer_size of 1 is used to transfer a byte at a time for so-called
69 | P a g e
"unbuffered" input/output. The most efficient value for transfer_size is the size of the
largest physical record the I/O channel is likely to have to handle.
Example#8:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 512
int main()
{ char buffer[BUFSIZE];
int fd;
int nread;
long total = 0;
if(( fd = open("myfile", O_RDONLY)) == -1) /* open "myfile" read only */
{ printf("Error in opening myfile\n");
exit(1);
}
while( (nread = read(fd,buffer, BUFSIZE)) >0) /* loops until EOL, shown by
return value of 0 */
{ total += nread; /* increment total */
}
printf("Total chars in my file : %ld\n",total);
exit(0);
}
0 (SEEK_SET) offset bytes into the file (The offset is measured from the beginning of the file;
usual actual integer value=0)
1 (SEEK_CUR) current position in the file plus offset (The offset is measured from the
current position of the file pointer; usual value =1 )
2 (SEEK_END) current end-of-file position plus offset (The offset is measured from the end
of the file; usual value =2)
70 | P a g e
The UNIX system file system treats an ordinary file as a sequence of bytes. No internal
structure is imposed on a file by the operating system. Generally, a file is read or written
sequentially -- that is, from beginning to the end of the file. Sometimes sequential reading
and writing is not appropriate. It may be inefficient, for instance, to read an entire file just to
move to the end of the file to add characters. Fortunately, the UNIX system lets you read and
write anywhere in the file. Known as "random access", this capability is made possible with
the lseek( ) system call. During file I/O, the UNIX system uses a long integer, also called a File
Pointer, to keep track of the next byte to read or write. This long integer represents the
number of bytes from the beginning of the file to that next character. Random access I/O is
achieved by changing the value of this file pointer using the lseek( ) system call. lseek()
enables random access into a file. To use it we need header files
#include<sys/types.h> and #include<unistd.h> .
Example#9:
a program fragment gives a position 16 bytes before the end of the file. From this example
it is clear that offset can be negative i.e it is possible to move backwards from the starting
point indicated by whence.
newpos = lseek(fd, -16, SEEK_END)
Example#10:
a program fragment that will append to the end of an existing file by opening the file,
moving to the end with lseek, and starting to write.
fd = open(filename, O_RDWR);
lseek(fd, 0, SEEK_END);
write(fd, outbuf, OBSIZE);
Example#11:
71 | P a g e
{
printf("datafile.dat opened for read/write access\n");
write(fd, message, sizeof(message));
lseek(fd, 0, 0); /* go back to the beginning of the file */ if (read(fd, buffer,
sizeof(message)) == sizeof(message)) printf("\"%s\" was written to datafile.dat\n",
buffer);
else
printf("*** error reading datafile.dat ***\n");
close (fd);
}
else
printf("*** datafile.dat already exists ***\n");
exit (0);
}
EXCERSICES
1. Update the code in example#8 to get the file name from the command line argument.