The C Programming Language  Datatypes, operators and expressions

C has very few datatypes
Data type Usage char single byte int integer float single precision floating point double double precision floating point 
short and long applies to integers only and hence can be omitted from the following declarations:
short int a;
long int b;

Compiler is free to choose sizes for datatypes subject to following conditions:
short
andint
are atleast 16 bits longlong
is atleast 32 bit longshort
is not longer thanint
int
is not longer thanlong
signed/unsigned
applies tochar
andint
both. 
signed/unsigned
applies tochar
andint
both. 
Enum Vs # Defines
 values can be generated for enums.
 enums can be printed in symbolic form by debuggers
 enums offer the chance of compiler checks

by default constant 2.3 will be treated as double until it is specified as 
2.3f (float)

Arbitrary bitsized patterns can be declared as:
'\ooo' (octal)
'\xab' (hex)

String constants can be concatenated at compile time:
#define mystr "hello," "world"
is equivalent to
#define mystr1 "hello,world"
usecase is in printf if you want to split a long string across multiple lines:
printf("hello,"
"world");is equivalent to:
printf("hello,\
world"); 
Variables must be declared before their use.

nonautomatic variables are initialized only once(before program starts executing) and the initializer has to be a constant. Automatic variables are initialized everytime the function or the block in which they are declared is hit. The initializer in this case can be any expression.

External and static variables are initialized to 0, while automatic variable has garbage value.

The result is implementation dependent if one tries to modify a const variable.

Leap year condition:
if (((year%4 == 0) && (year%100 != 0))  (year%400 == 0))

% operator cannot be applied to float and double

The direction of truncation for / and the sign of the result for % are machinedependent for negative operands, as is the action taken on overflow or underflow.

expressions connected by logical operators  && or  are evaluated from left to right and evaluation stops as soon as the truth or falsehood of the result is known. e.g.
if (ptr && ptr>value == val)
ptr needs to be checked before dereferencing its value. So, if ptr is null, the evaluation stops there only and no dereferencing of pointer takes place.
&& has higher precedence over  
automatic type conversion can convert a "narrow"(int) operand to a "wider"(float) one without losing information. However, the reverse operation loses information and may draw a compiler warning, but is not illegal.

float cannot be used as array index

Automatic type conversion:
 If either operand is long double, convert the other to long double
 Otherwise, if either operand is double, convert the other to double
 Otherwise, if either operand is float, convert the other to float
 Otherwise, convert char and short to int
 Then, if either operand is long, convert the other to long.

Floats arent automatically converted to double. In general, mathematical functions like those in <math.h> use double precision. float is only used to save space or make code portable on machines on which double precision arithmetic is very expensive.

char is just a small integer, so can be freely used in arithmetic expressions.

atoi implementation:
int atoi(char s[])
{
int i, n = 0;
for(i=0; s[i]>='0' && s[i] <= '9'; i++) {
n = n*10 + (s[i]  '0');
}
return n;
} 
ctype.h
provides methods for tests and conversion of characters e.g.tolower(), isdigit()
etc. 
definition of C gurantees that standard printable character set will never be negative, but arbitrary bitsequence stored in character variable may be negative or positive depending on the machine. For portability, specify signed/unsigned in such cases.

Comparison between signed and unsigned operands is machine dependent because they depend on the size of various integer types.

If integer is 16 bits and long is 32 bits then
1L < 1U
(unsigned integer gets promoted to signed long)1L > 1UL
(both are long, 1L gets promoted to unsigned long) 
If arguments are declared by a function prototype, it causes automatic coercion of any arguments when the function is called. In other words, there is no need to explicitly do a cast to double in the following case where int is passed as an argument:
double sqrt(double);
root = sqrt(2); 
increment(++) and decrement() operators can only be applied to variables; expression like
(i+j)++ is illegal
. 
/* remove all occurence of c from string s */
void squeeze(char s[], int c)
{
int i,j;
for (i=0, j=0; s[i] != '\0'; i++) {
if (s[i] != c) {
s[j++] = s[i];
}
}
s[j] = '\0';
} 
void strcat(char s[], char t[])
{
int i=0, j=0;
while(s[i++] != '\0');
while((s[i++] = t[j++]) != '\0');
} 
Right shifting(>>) an unsigned quantity will fill the vacated bits with zero, for signed quantity it will fill with bit signs(arithmetic shift) or with 0(logical shift)  what actually happens is machine dependent.

/*getbits(x,p,n) returns rightadjusted n bits from x starting from p. e.g. getbits(x,4,3) returns 3 bits from position 4,3 and 2. */
getbits(unsigned x, int p, int n)
{
return ((x >> pn+1) & ~(~0 << n));
} 
use
~0
to get implementation independent all set of 1s. e.g. on 32 bit system it will return 32 SET bits, on 16 bits system it will 16 SET bits. 
(n > 0) ? f : n
if f is float and n is int, the above conditional expression will be of type float irrespective of whether n is positive or not. (int gets promoted to float if other operand is float in an expression) 
Operator Precedence table:
Operator Associativity () [] > . left to right ! ~ ++  +(unary) (unary) * (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 
C doesnt specify the order in which operands are evaluated (except &&, , ?:, ','). So, there is no gurantee which function will be evaluated first out of f() and g(). So, if one function depends on variables modified in other  it might not work as expected.
x = f() + g()

There is no order of evaluation of expressions passed as function arguments. So, following is not correct:
printf("%d %d\n", ++n, power(2,n));
 there is no way to make sure ++n gets executed first and we pass the updated value in function power() 
C standard leaves the handling of sideeffects to the implementation of the compiler. e.g. the result of following is compiler and machine dependent:
a[i] = i++; 
Only thing the standard specifies is that all the sideeffects on arguments take effect before a function is called.