Last modified: 2023-04-08
C

| Year | Informal name | C Standard |
|---|---|---|
| 1972 | Birth | |
| 1978 | K&R C | |
| 1989 | ANSI C | |
| 1990 | C90 | ISO/IEC 9899:1990 |
| 1999 | C99 | ISO/IEC 9899:1999 |
| 2011 | C11, C1x | ISO/IEC 9899:2011 |
| 2018 | C17 | ISO/IEC 9899:2018 |
- C89 / ANSI is the most important standard, a must to know in C world
- C89 and C90 are practically identical
- C99 and C11 are nice to have
- It is recommended to use
gcc program.c -Wall -Wextra -pedantic -std=c89to give you additional feedback and code checks - Many things from C++ were backported into C99
- like
const, so you can avoid preprocessor's#define - and
stdint.h
- like
- specifications of C standards (source; they are technically drafts, but are valid)
Stuff to cover
*.cand*.cppcontain the implementation*.hcontain the definitions or prototypes- Preprocessor
- Header files
- Macros
- construction enclosed in
(and) - C language is stream oriented
- Memory Layout of C Programs
Operators
Sources:
See also:
-
Unary operators
- Perform action with single variable
- Examples:
++,++,!,sizeof, etc
-
Binary operators
- Perform action with two variables
- Examples:
+,-,*,>=, etc
-
Ternary operator
?- shorthand for
ifstatement
int larger;
if (a > b)
larger = a;
else
larger = b;
int larger;
larger = (a > b) ? a : b;
Comparison operators / relational operators
| Syntax | Operator |
|---|---|
| a == b | Equal to |
| a != b | Not equal to |
| a > b | Greater than |
| a < b | Less than |
| a >= b | Greater than or equal to |
| a <= b | Less than or equal to |
C++ also has this:
| Syntax | Operator |
|---|---|
| a <=> b | Three-way comparison |
Logic operators
| Operator | Function |
|---|---|
| a && b | AND |
| a || b | OR |
| !a | NOT |
- Non-zero values are
TRUE - Zero is always
FALSEjust like\0
Bitwise logic operators
| Operator | Function |
|---|---|
| a & b | AND |
| a | b | OR |
| ~a | NOT |
| a ^ b | XOR |
| a >> b | right shift |
| a << b | left shift |
Assignment operators
| Syntax | Operator name |
|---|---|
| a = b | Direct assignment |
| a += b | Addition assignment |
| a -= b | Subtraction assignment |
| a *= b | Multiplication assignment |
| a /= b | Division assignment |
| a %= b | Modulo assignment |
| a |= b | Bitwise OR assignment |
| a ^= b | Bitwise XOR assignment |
| a <<= b | Bitwise left shift assignment |
| a >>= b | Bitwise right shift assignment |
Member and pointer operators
| Syntax | Operator name |
|---|---|
| a[b] | Subscript |
| *a | Indirection (object pointed to by a) |
| &a | Address-of (address of a) |
| a->b | Structure dereference (member b of object pointed to by a) |
| a.b | Structure reference (member b of object a) |
Other operators
| Syntax | Operator name |
|---|---|
| a(b, c) | Function call |
| a, b | Comma |
| a ? b : c | Ternary conditional |
| sizeof a | sizeof |
| sizeof(type) | sizeof |
| (type) a | conversion / cast |
Variables
extern
static
Sources:
static:
- A static variable inside a function keeps its value between invocations.
- When you use
static int x = 0;, the variable is initialized to0only on creation and is not reset in later iterations. - Can be used instead of global variable.
- When you use
- A static global variable or a function is "seen" only in the file it's declared in.
- Static variables are allocated memory in data segment, not stack segment (see Memory Layout of C Programs)
- Static variables should not be declared inside structure. The reason is C compiler requires the entire structure elements to be placed together (i.e.) memory allocation for structure members should be contiguous.
In C++ the static can be used to define class attributes and methods shared between all objects of given class.
Arrays
Size of array
Sources:
sizeof with first element
int a[20];
size_t length = sizeof(a) / sizeof(a[0]);
sizeof with type
int a[20];
size_t length = sizeof(a) / sizeof(int);
Macro
#define NUM(a) (sizeof(a) / sizeof(*a))
for (i = 0; i < NUM(a); i++)
Compiler should be smart enough to not calculate the macro at compile time.
Libraries
math vs cmath vs math.h vs cmath.h
- those with
.hwill pollute your global namespace with a lot of junk, those without may or may not (no guarantees) cvsc++: prefixcis forC++and is missing the.hat the end
stdio.h
int printf ( const char * format, ... );- print C stringint putchar ( int character );- print single characterint puts ( const char * str);- print C string with newlineint scanf ( cost chat * format, ... );- read formatted data fromstdin- for example
scanf ("format", &var);, do not use&for string or array - stops at first white-space character
- discouraged to input strings because of possible buffer overflow
- rather use
fgets
- rather use
- for example
char * fgets ( char * str, int num, FILE * stream );
char input[64];
fgets(input,64,stdin);
Look into format specifiers to format data.
math.h
- usually use
double - Order of precedence
- equations are evaluated left to right
- multiplication and division are done first
- addition and subtraction
- parentheses used to prioritize some calculations
string.h
- C language does not have string, but rather arrays of characters
- final character of string is
nullcharacter (\0)
- final character of string is
char string[]where brackets can be empty if immediate assignment, otherwise length of desired string + 1 for null characterchar string[] = "hello";char string[6]; strcpy(string,"hello");
- string manipulation function are in
string.h
stdlib.h
void* malloc(size_t size);- successful allocation returns address
- failed allocation returns
NULLpointerNULLis a contant pointer, use it to check if allocation was succesful (not the same thing as\0)
char *sto;
sto = malloc( sizeof(char) * 1024 ); // want to store 1024 chars
if (sto == NULL){
printf("Unable to allocate memory\n");
return(1);
}
Pointers
- pointer is declared with
*operator - pointer type must match variable type it is pointing at
- when used without
*it represents an address - when used with
*it represents the value at the address
int pokey = 987;
int *p = &pokey;
printf("The address of 'pokey' is %p\n", &pokey);
printf("The address in 'p' is %p\n", p);
printf("The value of `pokey` is %d\n", pokey);
printf("The value of `*p` is %d\n", *p);
The address of 'pokey' is 0x7ffd437e4a8c
The address in 'p' is 0x7ffd437e4a8c
The value of `pokey` is 987
The value of `*p` is 987
Pointer arithmetic
int array[] = {11, 13, 17, 19};
int *aptr, *aptr2;
aptr = array;
aptr2 = &array[1];
printf("Elements is %d\n", *aptr);
printf("Elements is %d\n", *aptr2);
printf("Elements is %d\n", array[3]);
printf("Elements is %d\n", *(aptr+3));
Elements is 11
Elements is 13
Elements is 19
Elements is 19
Misc
- Required
main()function (this is the entry point) - operator
sizeofreturns number of bytes used by variable- can be even used of
struct
- can be even used of
- uninitialized variables contain garbage, this includes pointers
- modulo operator
%is for remainder after integer division
sizeof
struct stuff {
int a;
float b;
char c[32];
}
printf("Sizeof struct is %lu bytes", sizeof(struct stuff) );
returns:
Sizeof struct is 40 bytes