Memory Layout - Heap
- Global variables, static variables and program instructions get their memory in permanent storage area
- local variables are stored in Stack.
- The memory space between these two region is known as Heap area.
- This region is used for dynamic memory allocation during execution of the program.
- The size of heap keep changing.
Memory Allocation
- The header <stdlib.h> declares functions for storage allocation
- malloc returns a pointer to space for an object of a specified size, or NULL if the request cannot be satisfied. The allocated space is uninitialized
void *malloc(size_t size)
- free deallocates the space that previously allocated by calloc, malloc, or realloc
void free(void *P)
- size_t is an unsigned integer defined in stddef.h as (on my computer):
typedef long unsigned int size_t;
calloc
- calloc returns a pointer to space for an array of objects, each of size size, or NULL if the request cannot be satisfied. The space is initialized to zero bytes
void *calloc(size_t nobj, size_t size)
- realloc changes the size of the previously allocated memory by a new size.
- realloc returns a pointer to the new space, or NULL if the request cannot be satisfied, in which case the old allocated memory is unchanged.
void *realloc(void *p, size_t size)
Example
#include <stdio .h>
#include <stdlib .h>
#include <string .h>
int main() {
char ∗language ;
language = calloc ( 200, sizeof (char) );
if( language == NULL ) {
fprintf(stderr ,
"Error − ...\n");
}
else {
strcpy( language , "C programming language");
}
printf ("Language : %s\n" , language );
free ( language );
return 0;
}
realloc
int main() {
char ∗language ;
language = malloc( 25 ∗ sizeof(char) );
if( language == NULL ) {
fprintf(stderr , "...\n");
}
else {
strcpy( language , "C programming language");
}
language = realloc( language , 10 ∗ sizeof(char) );
if( language == NULL ) {
fprintf(stderr , "...\n");
}
else {
strcat( language , " tutorial");
}
printf ("Language : %s\n" , language );
free ( language );
return 0;
}
Pointer
int main() {
int ∗iptr = malloc (sizeof(int));
float ∗fptr = malloc (sizeof(float ));
double ∗dptr = malloc ( sizeof (double ));
∗iptr = 100;
∗fptr = 4.13f;
∗dptr = 459000.0;
printf("∗iptr: %d\n", ∗iptr);
printf("∗fptr: %.2f\n", ∗fptr);
printf("∗dptr: %.2f\n", ∗dptr);
free(iptr);
free(fptr);
free(dptr);
return 0;
}
File IO
- fopen opens the named file, and returns a stream, or NULL if the attempt fails
- FILE *fopen(const char *filename, const char *mode)
Legal values for mode include:
"r" | open text file for reading |
---|---|
"w" | create text file for writing; discard previous contents if any |
"a" | append; open or create text file for writing at end of file |
"r+" | open text file for update (i.e., reading and writing) |
"w+" | create text file for update; discard previous contents if any |
"a+" | append; open or create text file for update, writing at end |
- fflush causes any buffered but unwritten data to be written on an output stream
int fflush(FILE *Stream)
- on an input stream, the effect is undefined
- It returns EOF for a write error, and zero otherwise
- fflush(NULL) flushes all output streams
- fclose flushes any unwritten data for stream, discards any unread buffered input
int fclose(FILE *Stream)
- frees any automatically allocated buffer, then closes the stream
- It returns EOF if any errors occurred, and zero otherwise
Writing a file
- fputc() writes the character value to an output stream
int fputc( int c, FILE *fp );
- fputs() writes a string to an output stream
int fputs( const char *s, FILE *fp );
- fprintf write a string to an output stream
int fprintf(FILE *fp, const char *format, ...)
Reading a file
- fgetc() reads a character from the input file. he return value is the character read, or in case of any error, it returns EOF
- fgets() reads up to n-1 characters from an input stream. It copies the read string into a buffer, appending a null character to terminate the string.
- fscanf reads strings from a file, but it stops reading after encountering the first space character
Miscellaneous
Command-line Arguments
- In C it is possible to accept command line arguments
- Command-line arguments are given after the name of a program
- passed to the program by the operating system
- The full declaration of main looks like this:
int main ( int argc, char *argv[] )
#argc:number of command line arguments including the name of the program
#argv:list of all command line arguments
#argv[0]: the program name (or an empty string)
#argv[1] to argv[argc-1]: the actual command line arguments
Variable Arguments
- Sometimes, you would like to have a function that accept an arbitrary number of arguments
- for example a function that accepts any number of values and returns the average
- the last argument is written as ellipses, i.e. three dotes (...)
- the one just before the ellipses is always an int which will represent the total number variable arguments passed
Header file
- The header file stdarg.h provides the functions and macros to implement the functionality of variable arguments as follows
- Define a function with its last parameter as ellipses and the one just before the ellipses is always an int which will represent the number of arguments.
- Create a va_list type variable in the function definition
- Use int parameter and va_start macro to initialize the va_list variable to an argument list
- Use va_arg macro and va_list variable to access each item in argument list
- Use a macro va_end to clean up the memory assigned to va_list variable
Example
#include <stdio .h>
#include <stdarg .h>
double average(int num,...) {
va_list valist ;
double sum = 0.0;
inti;
va_start(valist , num);
for (i = 0; i < num; i++) {
sum += va_arg( valist , int );
}
va_end( valist );
return sum/num;
}
int main() {
printf("Average of 2, 3, 4, 5 =%f\n", average (4 , 2 ,3 ,4 ,5));
printf("Average of 5, 10, 15 =%f\n", average (3 , 5 ,10 ,15));
}
typedef
- The typedef keyword allows the programmer to create new names for types such as int
- Typedefs can be used both to provide more clarity to your code and to make it easier to make changes to the underlying data types
- in C, struct variables must be declared by a combination of the keyword struct and the name of the struct
typedef vs #define
- #define is a C-directive which is also used to define the aliases for various data types similar to typedef but with the following differences:
- typedef is limited to giving symbolic names to types only where as #define can be used to define alias for values as well
- typedef interpretation is performed by the compiler whereas #define statements are processed by the pre-processor
Preprocessors
- Preprocessors are a way of making text processing with your C program before they are actually compiled
- Before the actual compilation of every C program it is passed through a Preprocessor.
- The Preprocessor looks through the program trying to find out specific instructions called Preprocessor directives that it can understand.
- All Preprocessor directives begin with the # (hash) symbol
#define Substitutes a preprocessor macro.
#include Inserts a particular header from another file.
#undef Undefines a preprocessor macro.
#ifdef Returns true if this macro is defined.
#ifndef Returns true if this macro is not defined.
#if Tests if a compile time condition is true.
#else The alternative for #if.
#elif #else and #if in one statement.
#endif Ends preprocessor conditional.
#error Prints error message on stderr.
#pragma Issues special commands to the compiler,using a standardized method.