Background
Since many operations has to be accomplished with the assistance of hardware, but for most programs they can’t directly have access to hardware for safety. In this case, they will take operating system(a lower level software responsible for managing all of the resources on the system) as medium to access the hardware indirecly. The operating systems will check whether the call from the programs is legal.
Difference between system calls and library calls:
System call: transfer control to system
Library call: call a function found in library
Errors from system calls:
When a system call fails, it will create a global variable named errno(error number) to indicate the reason. We can use perror function to print a descriptive message based on the value of erron. Perror can take a string as argument to describe the condition.
Example:
perror prototype: print message to stderr, it can take an argument as prefix.
void perror (const char* prefix);
1
2
3
4
int x = someSystemCall();
if (x != 0 ){
perror("The error was: ");
}
Notice: When prints out the error messages, take care not to call anything might change erron like some system calls
int main(int argc, char ** argv)
argv[0]
contains the name of the programchar ** envp
, which is a pointer to an array of strings containing the values of environment variables.FILE*
FILE * fopen(const char * filename, const char * mode);
int fgetc(FILE * stream);
getc:
prototype: int getc(FILE* stream)
It is also used to read a character from the file. But unlike fgetc is a library function, it is preprocessor macro. It takes less time than a function call, but makes the code larger.
[!info] Shortcuts with stdin/stdout
reading one character from stdinint getchar (void);
write one character to stdout:
int putchar (int c);
fgets:
prototype: char * fgets(char * str, int size, FILE * stream);
The fgets function is useful when we want to read one line with a maximum length at a time.
char * str
: a pointer to an array in which to store the characters read from the file.
int size
: how much space is available for it to write data into
FILE * stream
: input file
The function will return str if it succeeds. It will return NULL either fails or encounters the end of the file.
It stops at the end of the line, or at the end of the input, or exceed the maximum array length.
It is the best way to read inputs by line, better than fscanf which takes the whole string as inputs.
size_t fread (void * ptr, size_t size, size_t nitems, FILE *stream);
void * ptr
: a pointer to data to write. Because it is a void type, it can write any kind of data.size_t size
: the size of each itemsize_t nitems
: how many such items should be read from the streamint getchar (void);
printf
except that it takes an additional argument of type * FILE
to specify the output location. Return number of characters printed or negative numbers on failure.int fputc (int c, FILE* stream)
int fputs (const char*s, FILE* stream);
int puts (const char* s);
size_t fwrite(const void * ptr, size_t size, size_t nitems, FILE * stream);
int putchar (int c)
int scanf (const char* format, ...);
reads formatted input from stdin.int fscanf(FILE *stream, const char* format, ...);
int sscanf (const char* s, const char* format, ...);
int printf (const char* format, ...);
writes formatted output to stdoutint fprintf (FILE* stream, const char* format, ...);
int snprintf (char* s, size_t size, const char* format, ...);
fclose:
prototype: int fclose(FILE * stream);
prototype: cmd1 | cmd2
We can sue pipe operator to redirect the output of the first file to the input of the second file.
<
read stdin from a file
>
write stdout to a file
>>
append stdout to an existing file
Use |&
and >&
to include stderr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include<stdarg.h> //include C library function which supports variadic functions
//declare stream variable for the output to store
static FILE* logfile = NULL;
int printlog (const char* fmt, ...)
{
//our first task is to open the file
if (NULL == logfile) {
//open the stream file ,format "a" to indicate append to end of existing file
logfile = fopen ("the_log", "a");
if (NULL == logfile){
return -1;
}
}
//declare a variable argument list using va_list
va_list args;
//va_start is a preprocessor macro that starts the variable-length list after the specified argument-in this case, fmt
va_start (args, fmt);
//call vfprintf to handle variable arguments
return vfprintf (logfile, fmt, args);
//This fucntion will return number of characters printed or a negative value on failure
}
Our task:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//input: tre structure, the file name to write
//return value: 1 on success, 0 on failure
int32_t write_pyr_tree_ASCII (pyr_tree_t* p, const char* fname)
{
FILE* out;
if (NULL == (out = fopen(fname, "w"))){
return 0;
}
//start by writing number of nodes to know the size of the array at the beginning
fprintf (out, "%d\n, p->n_nodes);
//print each non-leaf node
int32_t first_leaf = (p->n_nodes + 2) / 4;
int32_t i;
for (i = 0; first_leaf > i; i++){
fprintf(out, "%d %d %d\n", p->node[i].x, p->node[i].y_left), p->node[i].y_right};
}
//print leaf node
for ( ; p->n_nodes >i; i++) {
fprintf (out, "%d\n", p->node[i].id);
}
return (0 == fclose(out));
}
//binary version
int32_t write_pyr_tree_binary (pyr_tree_t* p, const char* fname)
{
FILE* out;
if (NULL == (out = fopen(fname, "w"))){
return 0;
}
//apply fwrite to write binary data, directly write the node data
int32_t rval = (1 == fwrite(&p->n_nodes, sizeof(p->n_nodes), 1, out) && p->n_nodes == frite (p->node, sizeof(p->node[0]), p->n_nodes, out));
fclose (out);
return rval;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//reconstruct a pyramid tree from binary file
pyr_tree_t* read_pyr_tree_binary (const char* fname)
{
FILE* in; //input stream
pyr_tree_t* p; //new pyramid tree
int32_t count; //number of nodes in a file
if (NULL == (in = fopen(fname, "r")) || 1 != fread (&count, sizeof(count), 1, in)){
if (NULL != in){
fclose (in);
}
}
return 0;
//Allocate space for pyramid tree and node array
if (NULL (p = malloc(sizeof(*p))) || NULL (p->node = malloc(sizeof(p->node[0])*count)))){
if (NULL != p) free(p);
fclose(in);
return NULL;
}
//reconstrcuct the tree
p->n_nodes = count;
if (p->n_nodes != fread (p->node, sizeof(p->node[0]), p->n_nodes, in)){
free_pyramid_tree (p);
fclose (in);
return NULL;
}
fclose (in);
return p;
}