C Notes
Style guide
I agreed with most of what was said here
Summary:
79 column rule (nope...)
_
delimiterg_
prefix for globalsUPPERCASE for
enum
,#define
Basics
// arrays
char buf[2] = ""; // same as: char buf[10] = {0, 0};
char *p1 = "String"; // NOTE: this is read-only
char p2[] = "String";
char p3[7] = "String"; // NULL terminated
// length of an array
int arr[4] = {1, 2, 3};
int num_elements = sizeof(arr)/sizeof(arr[0]); // total_size/element_size
strncpy(p3, p2, sizeof(p1)-1); // strncpy doesn't auto NULL terminate
// ternary operator
// boolean_expr ? true : false;
int x = (true)
? 1
: 2;
((i < 3) ? i : j) = 7; // more confusing example up example
(false) ? printf("Always false!\n")
: printf("Won't reach here ever..\n");
printf
%6d
: print as a decimal integer with a width of at least 6 wide.%4f
: print as a floating point with a width of at least 4 wide.%.4f
: print as a floating point with a precision of four characters after the decimal point.%3.2f
: print as a floating point at least 3 wide and a precision of 2.%.10s
: prints the string, but print only 10 characters of the string.%-10s
: prints the string, but prints at least 10 characters. If the string is smaller “whitespace” is added at the end.
static
A
static
variable inside a function keeps its value between invocations.A
static
global variable or a function is "seen" only in the file it's declared in
void foo() {
int a = 10; static int sa = 10;
a += 5;
sa += 5;
printf("a = %d, sa = %d\n", a, sa);
}
int main() {
int i;
for (i = 0; i < 10; ++i)
foo();
}
/*
PRINTS:
a = 15, sa = 15
a = 15, sa = 20
a = 15, sa = 25
*/
int var1; // has global scope and static allocation
static int var2; // has file scope and static allocation
enum
// default values are 0, 1..
// to get a string representation, you need to have an
// array of strings for each index - or macro hacks
// the elements must be unique in its scope - can't have
// two 'MON', even if different enums
// UPPERCASE_UNDERSCORE is standard
typedef enum weekday {
MON, TUES, WED, THURS, FRI, SAT, SUN
} weekday; // so we don't need to do this: enum weekday day = Mon;
typedef enum boolean {
TRUE = 1, // we can assign them values instead
FALSE = 0 // and they can have the same values
} boolean;
boolean t_f = FALSE;
Stack and Heap
void *foo(int **second_array) {
// malloc int array[10] in heap like normal
int *ptr = (int *)malloc(sizeof(int)*10);
// malloc a second array using the reference passed in
// note: de-referencing will point to the original pointer!
*second_array = (int *)malloc(sizeof(int)*10);
// casting as (void *) can be useful for allocating
// memory for 'generic' types
// you need to remember to free this pointer!
return (void *)ptr;
}
int main(int argc, char **argv) {
// your normal stack variables
// generally there's a stack size limit hence you normally
// don't declare super large variables here
// also malloc'ing memory allows it to survive the life cycle
// of this function - useful for nested functions
int stack_var = 10;
int *reference_pointer; // we want to obtain a array of ints
foo(&reference_pointer); // so we pass by reference
free(reference_pointer);
return 0;
}
Prefix and Postfix operands
Prefix operator
++x
, returns the value of its operand after adding one.Postfix operator
x++
, returns the value of its operand before adding one.
int i = 10;
int j = ++i; // j == 11
int k = i++; // k == 11
Operator precedence
2
a++
a--
Suffix/postfix increment and decrement
Left-Right
type()
type{}
Functional cast
a()
Function call
a[]
Subscript
.
->
Member access
3
++a
--a
Prefix increment and decrement
Right-to-left
+a
-a
Unary plus and minus
!
~
Logical NOT and bitwise NOT
(type)
C-style cast
*a
Indirection (dereference)
&a
Address-of
sizeof
Size-of1
new
new[]
Dynamic memory allocation
delete
delete[]
Dynamic memory deallocation
4
.*
->*
Pointer-to-member
Left-to-right
5
a*b
a/b
a%b
Multiplication, division, and remainder
6
a+b
a-b
Addition and subtraction
7
<<
>>
Bitwise left shift and right shift
8
<
<=
For relational operators <
and ≤
respectively
>
>=
For relational operators >
and ≥
respectively
9
==
!=
For relational operators =
and ≠
respectively
10
a&b
Bitwise AND
11
^
Bitwise XOR (exclusive or)
12
`
`
Bitwise OR (inclusive or)
13
&&
Logical AND
14
`
`
15
a ? b : c
Ternary conditional2
Right-to-left
throw
throw operator
=
Direct assignment (provided by default for C++ classes)
+=
-=
Compound assignment by sum and difference
*=
/=
%=
Compound assignment by product, quotient, and remainder
<<=
>>=
Compound assignment by bitwise left shift and right shift
&=
^=
`
=`
Compound assignment by bitwise AND, XOR, and OR
16
,
Comma
Left-to-right
1: The operand of
sizeof
can't be a C-style type cast: the expressionsizeof (int) * p
is unambiguously interpreted as(sizeof(int)) * p
, but notsizeof((int)*p)
.2: The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to
?:
is ignored.
Associativity
Operators that have the same precedence are bound to their arguments in the direction of their associativity.
For example the expressions:
a = b = c
is parsed asa = (b = c)
and not as(a = b) = c
because of right-to-left associativity of assignment.a + b - c
is parsed as(a + b) - c
and not asa + (b - c)
because of left-to-right associativity of addition and subtraction.
Associativity specification is redundant for unary operators and is only shown for completeness: unary prefix operators always associate right-to-left (delete ++*p is delete(++(*p)))
and unary postfix operators always associate left-to-right (a[1][2]++ is ((a[1])[2])++)
.
Note that the associativity is meaningful for member access operators, even though they are grouped with unary postfix operators: a.b++
is parsed (a.b)++
and not a.(b++)
.
Last updated