Get started !
online LTE test
online C test

Updated or New
5G NR Data Rate calculator New
5G NR TBS calculator New
5G NR UE Registration New
Python programming
C++ programming
MIMO for 3GPP Developer - 2
Uplink power control
MIMO for 3GPP Developer
NR ARFCN and GSCN
5GS Interfaces



About
Feedback
Information Theory
Modulation
Multiple Access
DSP
OSI Model
Data Link layer
SS7
Word about ATM
GSM
GPRS
UMTS
WiMAX
LTE
CV2X
5G
Standard Reference
Reference books
Resources on Web
Miscellaneous
Mind Map
Magic MSC tool
Bar graph tool
C programming
C++ programming
Perl resources
Python programming
Javascript/HTML
MATLAB
ASCII table
Project Management

another knowledge site

3GPP Modem
Simulator


Sparkle At Office comic strip

C programming guide

Index
1)Books on C
2)main declarations
3)Strange i=i++;
4)x=y=z=3
5)3["0123456789abcdef"] works ?
6)\r and \n
7)Declaring structure having an element pointing to structure of its own type. Useful for implementing linked list.
8)-1>>1
9)Reading or writing complex declarations
10)printf/scanf format characters
11)Reading command line arguments
12)Variable number of arguments
13)Precedence and associativity of operators
14)Array initialisation and assignment
15)Big-endian or Little-endian ?
16)string.h
17)sizeof character constant is 1 ?
18)Definition and declaration
19)static effect
20)bitmap implementation
21)Generic Stack implementation
22)What is void pointer anyway ?
23)Reading a file
24)math.h library
25)stdio.h
26)Predefined macros (or names as K&R calls it)
27)Storage classes
28)ctype.h library
29)stdlib.h library
30)Max and minimum values for int, float, etc. limits.h library
31)Glossary

Programs compiled with gcc 3.4.5 on Dell Windows-XP.

1) Books on C The one and only,

     The C Programming Language by Kernighan and Ritchie

To gain further depth in C,

     C Programming FAQs by Steve Summit

2) main declarations main has only two valid declarations:

int main(void); int main(int argc, char** argv);

Following declarations gets converted to one of the above two declarations:

main(); void main(void); main(void); int main(int argc, char *argv[]); int main(int argc, char argv[][]);


3) Strange i=i++; Seemingly logical behaviour of i=i++; is i incremented by one at the end. But is it that simple or logical for comiler too ? Answer is No !

"i++" supposed to "use i value" and "then increment the same". In statement i=i++;, value of i is being used to assign to i itself and that is sort of an anamoly .... i gets modified twice in i=i++; one due to assignment and other due to side-effect of post-increment.

As per C standards, this is not correct !! So the behaviour of i=i++; statement (and any of the following statements) is considered to be "undefined" (even if syntactically correct).

i=++i; Variations of (i++)*(i++) a[i]=i++;

Please refer C Programming FAQs by Steve Summit (section 3) for detailed discussion on the topic.

4) x=y=z=3 The statement is valid and it does what we expect i.e. it makes value of x, y, and z 3. The reason it works is because "=" operator has right-to-left associativity. So the statement assigns 3 to z, then assigns z to y, and then assigns y to x.

5) 3["0123456789abcdef"] works ? Yes, it does work. Compiler interprets both 3["0123456789abcdef"] and "0123456789abcdef"[3] same way ! The reason seems to be in the way C thinks of an array (as an constant pointer). array[index] is as good as *(array + index) or *(index + array) (addition operator works in the same way irrespective of order of operands).

6) \r and \n \r moves the cursor to the left-most position of *current* line.
\n moved the cursor to the left-most position of *next* line.

7) Declaring structure having an element pointing to structure of its own type. Useful for implementing linked list. There are number of ways to do it:

typedef struct struct_type_state state ; struct struct_type_state { int int_state_id; state * ptr_next_state; };

or

typedef struct struct_type_state { int int_state_id; struct struct_type_state * ptr_next_state; } state;

or

struct struct_type_state { int int_state_id; struct struct_type_state * ptr_next_state; }; typedef struct struct_type_state state;


8) -1>>1 -1 is (stored as 2's complement) 0xFFFFFFFF in (32 bit) machine. Right-shifted any number of times) will have the same value i.e. -1>>1 = -1.

So following statement will increment i by one.

i = i - (-1>>7);

9) Reading or writing complex declarations Example: Declare an array of function pointers returning pointer to integer.

1st method (left-to-right or in-to-out):
array - a[]
of function pointers - (* (a[]) )() (braces around a[] are optional)
returning pointer - *(* a[])()
to integer - int *(* a[])()

2nd method (right-to-left or out-to-in):
integer - int
pointer to - int *
function pointers returning - int *(*)()
array of - int *(* a[])()

10) printf/scanf format characters
% printf scanf
d int (signed decimal) int* (decimal)
i int (signed decimal) int* (decimal, octal, hexa)
u int (unsigned decimal) unsigned int* (unsigned decimal)
o int (octal without leading 0) int* (octal with/without leading zero)
x,X int (hexa without leading 0x or 0X) int* (hexa with/without leading 0x or 0X)
c int (a character) char* (character)
s char* (till \0 or given precision) char* (non-whitespace characters)
f double (signed fraction) float* (signed fraction, e/E notation also accepted)
e,E double (signed fraction in e/E notation) float* (signed fraction, e/E notation also accepted)
p void* (implementation dependent) void* (implementation dependent)
n int* (number of characters printed so far is put into it) int* (number of characters printed so far is put into it)
% print % literal %
[...] NA longest string of input characters; characters given in [...].
[^...] NA longest string of input characters; characters other than given in [...].


11) Reading command line arguments Below example illustrate reading of number and string from command line arguments.

#include <stdio.h> #include <stdlib.h> /* for atoi */ int main(int argc, char** argv) { unsigned int integer = 0; char* string = NULL; printf("argc=%d\n", argc); /* number of arguments */ printf("argv[0]=\"%s\"\n", argv[0]); /* name of executable */ printf("argv[1]=\"%s\"\n", argv[1]); /* integer */ printf("argv[2]=\"%s\"\n", argv[2]); /* string */ integer = atoi(argv[1]); string = argv[2]; printf("integer = %d\n", integer); printf("string = \"%s\"\n", string); printf("----\n"); return 0; }

argc=3 argv[0]="./a.out" argv[1]="786" argv[2]="Hello there !" integer = 786 string = "Hello there !" ----

12) Variable number of arguments Example:

#include <stdio.h> #include <stdarg.h> int algorithm( char* parameters, ... ); int main(void) { printf( "algorithm: %d\n", algorithm( "ioioi", 5, '+', 2, '-', 3 ) ); } int algorithm( char* parameters, ... ) { va_list argp; int result = 0; char *pp; char operation = '+'; va_start( argp, parameters ); for( pp = parameters; *pp != '\0'; ++pp ) { switch( *pp ) { case 'i': switch( operation ) { case '+': result += va_arg( argp, int ); break; case '-': result -= va_arg( argp, int ); break; default : /* ERROR */ break; } break; case 'o': operation = (char)va_arg( argp, int ); break; default: /* ERROR */ break; } } va_end( argp ); return result; }


Functions using variable number of arguments must have at least one argument before "...". Typically this would be char* having information about type of (variable) arguments that would be following.

13) Precedence and associativity of operators
unary + - * right to left
() [] -> . left to right
! ~ ++ -- + - * & (cast type) sizeof right to left
* / % left to right
+ - left to right
<< >> left to right
< <= > >= left to right
== != left to right
& left to right
^ left to right
| left to right
&& left to right
|| left to right
?: right to left
= += -= *= /= %= &= ^= |= <<= >>= right to left
, left to right


14) Array initialisation and assignment Array can be initialised, but can not be assigned values as illustrated in an example below.

char c_array[5] = "test"; /* Initialisation */ char c_array2[5]; int i_array[2] = { 1, 2 }; /* Initialisation */ int i_array2[2]; c_array2 = "test"; /* Assignment - compiler error */ i_array2[] = { 1, 2 }; /* Assignment - compiler error */ i_array2 = i_array; /* Assignment - compiler error */

But here is something that does work !

char *c_ptr; c_ptr = "test ok";

Even following works !

void array_assign( char c_array[] ); int main(void) { char c_array2[5]; array_assign( c_array2 ); } void array_assign( char c_array[] ) { c_array = "test"; }

This works because of special treatment to string constants and because array is passed as pointers to function.

15) Big-endian or Little-endian ? Following is simple test to determine endianess of machine.

int i=1; if( *(char*)&i == 1 ) { printf( "Little-endian machine\n" ); } else { printf( "Big-endian machine\n" ); }

Graphically,

  0 <--- Big-endian pointer
  0
  0
  1 <--- Little-endian pointer


16) string.h Commonly used ones:

char *strcpy(char *s1, char *s2) Copy s2 to s1, return s1.
char *strncpy(char *s1, char *s2, int n) Copy n characters.
char *strcat(char *s1, char *s2) Append s2 to s1, return s1.
char *strncat(char *s1, char *s2, int n) Append n characters.
int strcmp(char *s1, char *s2) Compare, return
 <0 if s1<s2,
   0 if s1=s2, and
 >0 if s1>s2.
int strcmp(char *s1, char *s2, int n) Compare n characters.
char *strchr(char *s1, char*s2) return pointer to first occurence of s2 in s1.
char *strrchr(char *s1, char*s2) return pointer to last occurence of s2 in s1.
size_t strlen(char *s1) return length of s1.


17) sizeof character constant is 1 ? No. sizeof( 'c' ) is 4 (32 bit machine).

Character constant is stored as an integer (4 bytes) rather than a character (1 byte) !

18) Definition and declaration Declaration indicate type of variable.
Definition mean variable is "created" i.e. storage (as per declaration of variable) is allocated.

For example int i; is declaration and definition whereas extern int i; is just a declartion.

19) static effect We know that if used in function, static allows to have permanent variable inside function accessible only to function. Another (often forgotten) effect of static is: if used in file, the variable would be accessible inside the file, but not outside.

20) bitmap implementation Below is a simple bitmap implementation:

#define BITMAP_SIZE 64 #define BYTE_SIZE 8 void set_bit( unsigned int n ); void reset_bit( unsigned int n ); int is_set( unsigned int n ); static unsigned char bit_map[ BITMAP_SIZE/BYTE_SIZE ]; void set_bit( unsigned int n ) { int byte_number = (n-1) / BYTE_SIZE; int bit_number = (n-1) % BYTE_SIZE; if( byte_number &lt; (BITMAP_SIZE/BYTE_SIZE) ) bit_map[byte_number] = bit_map[byte_number] | (1&lt;&lt;bit_number); } void reset_bit( unsigned int n ) { int byte_number = (n-1) / BYTE_SIZE; int bit_number = (n-1) % BYTE_SIZE; bit_map[byte_number] = bit_map[byte_number] & ~(1&lt;&lt;bit_number); } int is_set( unsigned int n ) { int byte_number = (n-1) / BYTE_SIZE; int bit_number = (n-1) % BYTE_SIZE; if( bit_map[byte_number] & (1&lt;&lt;bit_number) ) return 1; return 0; } void display_bitmap( void ) { int ctr; int bctr; for( ctr=(BITMAP_SIZE/BYTE_SIZE - 1); ctr&gt;=0; --ctr ) { for( bctr=(BYTE_SIZE-1);bctr&gt;=0;--bctr ) { if( bit_map[ ctr ] & (1&lt;&lt;bctr) ) { printf( "%1d", 1 ); } else { printf( "%1d", 0 ); } } printf( " " ); } printf( "\n" ); }


21) Generic Stack implementation Below is a simple implementation generic stack that can store elements of any type.

void push( void *element ); void *pop(); typedef struct struct_type_item item ; struct struct_type_item { void *element; item *next; }; static item *root = NULL; void push( void *element ) { item *to_put = (item*) malloc( sizeof(item) ); to_put-&gt;element = element; to_put-&gt;next = NULL; if( root ) { to_put-&gt;next = root; root = to_put; } else { root = to_put; } } void *pop() { if( root ) { void *tmp = root; void *element; element = root-&gt;element; root = root-&gt;next; free( tmp ); return element; } else { return NULL; } } void display_stack( void ) { item* tmp = root; while( tmp ) { printf( "--&gt;%d&lt;---\n", *(int*)tmp-&gt;element ); tmp = tmp-&gt;next; } }


22) What is void pointer anyway ? void pointers are ways to write code that can work on generic data types; this is illustrated in generic stack implementation.

Following example shows how C treats void pointers:

#include <stdio.h> struct test_struct { int x; int y; int z; }; int main(void) { struct test_struct t_struct[3]; void *void_p1=(void *)&(t_struct[0]); void *void_p2=(void *)&(t_struct[1]); struct test_struct *ts_p1=(void *)&(t_struct[0]); struct test_struct *ts_p2=(void *)&(t_struct[1]); printf( "Size of test_struct \n" ); printf( "\t-using void pointers is %d and\n", (void_p2 - void_p1) ); printf( "\t-using structure pointers is %d.\n", (ts_p2 - ts_p1) ); printf( "\t-using sizeof operator is %d.\n", sizeof(struct test_struct) ); }

Size of test_struct -using void pointers is 12 and -using structure pointers is 1. -using sizeof operator is 12.

23) Reading a file Below program takes file name from the command line and output the file content on console (similar to Linux/Unix command "cat").

#include <stdio.h> #define MAX_LINE_BUFFER_LENGTH 255 int main(int argc, char** argv) { char* file_name = NULL; FILE* file_handle = NULL; char line_buffer[MAX_LINE_BUFFER_LENGTH]; file_name = argv[1]; printf("file_name = \"%s\"\n", file_name); file_handle = fopen(file_name, "r"); /* "r" => reading */ if(file_handle == NULL) return 1; /* file open error */ while(fgets(line_buffer, sizeof(line_buffer), file_handle)) { printf("%s", line_buffer); } fclose(file_handle); printf("----\n"); return 0; }

file_name = "sample-text-file.txt" This is a sample file. It has 2 lines. ----

24) math.h library
sin(d) sine of d
cos(d) cosine of d
tan(d) tangent of d
asin(d) sine-1 of d
acos(d) cosine-1 of d
atan(d) tangent-1 of d
sinh(d) hyperbolic sine of d
cosh(d) hyperbolic cosine of d
tanh(d) hyperbolic tangent of d
exp(x) ex
log(x) ln(x)
log10(x) log10(x)
pow(x,y) xy
sqrt(x) √x
ceil(x) smallest integer not less than x
floor(x) largest integer not greater than x
fabs(x) |x| (abosolute value)
modf(fraction, double *ip) return fractional part of fraction and store integral part in ip
fmod(x, y) fractional part of x/y


25) stdio.h
int printf(const char *format, ...) output on stdout stream
int fprintf(FILE *stream, const char *format, ...) output on stream. Special case is printf (where stream is stdout).
int sprintf(char *s, const char *format, ...) output to string str.
int scanf(const char *format, ...) read from stdin stream.
int fscanf(FILE *stream, const char *format, ...) read from stream. Special case is scanf (where stream is stdin).
int sscanf(char *str, const char *format, ...) read from string str.
FILE *fopen(const char *file, const char *mode) open file. Modes are "r" (read), "w" (write), "a" (append), "r+" (reading and writing), "w+" (create file; discard previous content if any). For binary files, prefix b, e.g. "rb".
FILE *freopen(const char *file, const char *mode) re-open file with different mode. Usually used for (default opened) stdout, stdin, and stderr streams.
int fflush(FILE *stream) flush buffered unwritten (if any) content to output stream.
int fclose(FILE *stream) flush and close earlier opened file with fopen.
int remove(const char *file) delete file.
int fgetc(FILE *stream) or
int getc(FILE *stream)
get next character from input stream.
int getchar(void) equivalent to getchar(stdin).
char *fgets(char *s, int n, FILE *stream) string of length n - 1 from input stream. It stops for newline.
char *gets( char *s) read next input line from stdin; newline replaced by \0.
int fputc(int c, FILE *stream) or
int putc(int c, FILE *stream)
write next character to output stream.
int putchar(int c) equivalent to putc(stdout).
int fputs(const char *s, FILE *stream) write string s to output stream.
int puts(const char *s) write s and newline to stdout.
size_t fread(void *p, size_t sz, size_t n, FILE *stream) read n elements of size sz into p from input stream and return number of elements read. feof and ferror is to be used to determine if end of file reached or error happened respectively.
int feof(FILE *stream) check if end-of-file reached.
int ferror(FILE *stream) check for error in last file operation.
int fwrite(const void *p, size_t sz, size_t n, FILE *stream) write n elements of size sz from p to output stream and return number of element written.
int fseek(FILE *stream, long offset, int origin) set next read/write to offset from origin. For binary file, origin would be SEEK_SET(beginning), SEEK_CUR(current), or SEEK_END(end of file). For ascii/text stream, offset must be zero or a value returned by ftell along with origin=SEEK_SET. It returns zero on success.
long ftell(FILE *stream) return current file position or -1L on error.


26) Predefined macros (or names as K&R calls it)
__LINE__ Current source line number
__FILE__ Name of file
__DATE__ Date of compilation, "Mmm dd yyyy"
__TIME__ Time of compilation, "hh:mm:ss"
__LINE__ Current source line number
__LINE__ Current source line number


27) Storage classes
Storage Declaration keywords Initial value Storage place Scope Life
automatic auto, register, default for variables declared without any storage keyword within {} not automatically initialised stored in stack memory, register variables may be stored in processor registers local to block discarded upon exit from block
static static, extern, default for variable declared in file (outside {}) initialised to zero automatically stored in main memory till end of execution of program global except when static keyword used alive till end of execution of program


28) ctype.h library
int isupper(int c) upper-case letter
int islower(int c) lower-case letter
int isdigit(int c) decimal digit
int isalpha(int c) alphabetic character (one of isupper and islower would be true)
int isalnum(int c) alphanumeric character (one of isalpha and isdigit would be true)
int isxdigit(int c) hexadecimal digit
int isspace(int c) space,carriage return(\r),newline(\n),tab(\t),vertical tab(\v),form feed(\f)
int iscntrl(int c) control character
int toupper(int c) convert to upper-case letter if islower is true otherwise return same back.
int tolower(int c) convert to lower-case letter if isupper is true otherwise return same back.


29) stdlib.h library
void *malloc(size_t sz) allocate (heap) memory of sz bytes and return generic address (void).
void *calloc(size_t n, size_t sz) allocate (heap) memory of n * sz bytes and return generic address (void).
void *realloc(void *p, size_t sz) re-allocate p to size sz bytes and return generic address (void) of new allocation.
void free(void *p) free memory previously allocated by malloc, calloc, and realloc.
void exit(int status) normal program termination
void abort(void) abnormal program termination
int system(const char *cmd) execute command in OS enviornment
char *getenv(const char *evar) get environment variable value
int rand(void) pseudo-random integer from 0 to RAND_MAX.
int srand(unsigned int seed) pseudo-random integer from 0 to RAND_MAX with seed.
void *bsearch(const void *skey, const void* base, size_t n, size_t sz, int (*cmp)(const void *x, const void *y) ) Binary search in base list containing n elements of size sz for skey. Comparison function is to be supplied as parameter cmp. Comparison function to return negative if x<y, zero if x=y, positive if x>y.
void *qsort(const void* base, size_t n, size_t sz, int (*cmp)(const void *x, const void *y) ) Sort base list having n elements of size sz. Comparison function is to be supplied as parameter cmp. Comparison function to return negative if x<y, zero if x=y, positive if x>y.


30) Max and minimum values for int, float, etc. limits.h library
CHAR_BIT
CHAR_MAX (or UCHAR_MAX or SCHAR_MAX)
CHAR_MIN (or SCHAR_MIN)
INT_MAX
INT_MIN
LONG_MAX
LONG_MIN
SHRT_MAX
SHRT_MIN
UINT_MAX
ULONG_MAX
USHRT_MAX


31) Glossary
FILE - 23
argc - 11
argv - 11
big-endian - 15
fclose - 23
fgets - 23
fopen - 23
little-endian - 15
main - 2
va_arg - 12
va_end - 12
va_list - 12
va_start - 12
void - 22



© Copyright Samir Amberkar 2023-24