C

File size
14.9KB
Lines of code
403

C

Comments

// single-line comments
/* multi-line
comments
look
like 
this */

Importing headers

// ---------- HEADER ----------
    // headers are the equivalent of Python's modules
    // their contents are syntatically similar to C source files but the file format ends in .h

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

Printing

// ---------- PRINT ----------
    // printf is print formatted, it does not print a newline by default
        // %c for char
        // %s for strings (char[])
        // %d or %I for short signed
        // %u for short unsigned
        // %ld for long signed
        // %lu for long unsigned
        // %x for unsigned hexadecimal
        // %o for unsigned octal
        // %f for float
        // %lf for double
        // %p for pointer
        // %% to print out %

printf("watermelon\n");
printf("%d\n", 0); // prints 0

// ---------- RECEIVE INPUT ----------
    // scanf takes in an input
    // &input specifies the memory address where we store the input value of type int

int input;
scanf("%d", &input);

// ---------- SPECIAL CHARACTERS ----------

'\n'; // newline character
'\t'; // tab character (left justifies text)
'\v'; // vertical tab
'\a'; // alert (bell) character
'\f'; // new page (form feed)
'\r'; // carriage return
'\b'; // backspace character
'\0'; // NULL character. Usually put at end of strings in C.
'\\'; // backslash
'\?'; // question mark
'\''; // single quote
'\"'; // double quote
'\xhh'; // hexadecimal number. Example: '\xb' = vertical tab character
'\0oo'; // octal number. Example: '\013' = vertical tab character

Types

// ---------- TYPE ----------
    // sizeof() operator returns the size of a given data type
    // char => 1 byte, but can be larger, single quotation marks, also known as a character literal
    // char[] => C's version of strings, take 1 byte * length of array, double quotation marks
    // int => 4 bytes, integer types may be signed or unsigned like in Rust
        // short => 2 bytes
        // long => 4 - 8 bytes
        // long long => 8 bytes or more
    // float => 32-bit 
        // double => larger float, 64-bit
    // 1 or 0 => C's version of booleans, 0 being false, 1 being true (though technically any non-0 value is true)

char x_char = 'y'; // char literals are single quoted
char x_str[20] = "This is a string"; // strings are double quoted
int x_int = 0;
short x_short = 0;
long x_long = 0;
long long x_long_long = 0;
unsigned int y_int = 10;
signed short z_int = -5;
signed long long a_int = -1009;
float x_float = 0.01;
double x_double = 0.0;

// VARIABLES
    // declared once, value can be reassigned later

// CONST
    // declared once, value can only be assigned once
    // const stated before type of constant value

const float eg_float = 5.8;
const char eg_char = 'a';
const char *str_literal = "this is good practice"; // for string literals you don't intend to change, it is good practice to declare them as a constant and a pointer to a char (first element of the char array), which represents a char array

Data structures

// ---------- ARRAY ----------
    // ordered list of elements of the same data type
    // initialized with a fixed size and type, though array elements are mutable
    // character array is a string (C has no built-in string type)
    // arrays are curly-braced in C

char my_char_array[20]; // allocates 1 * 20 = 20 bytes of space for the char array in memory
char my_int_array[20]; // allocates 4 * 20 = 80 bytes of space for the int array in memory
int an_eg_int_array[10] = {1,2,3,4,5,6,7,8,9,10}; // note the curly braces
char an_eg_char_array[5] = {'a','b','c','d','e'}; // another valid char array, although this also evaluates to "abcde"

// ARRAY INITIALIZER
    // {} initializes an array with default value of 0 past the specified values

int my_array[20] = {0}; // this initializes an int array of 80 bytes with each int being 0
int another_array[10] = {1,2}; // this initializes an int array [1,2,0,0,0,0,0,0,0,0], the remaining 8 unspecified values being 0
int yet_another_array[] = {0}; // note that not specifying the size of the array will result in an array of [0] with length 1

// ARRAY INDEXING 

my_array[0]; // returns 0, the element at index 0 is 0
my_array[10] = 2; // reassigns the element at index 10 to be 2
printf("%d\n", my_array[10]); // returns 2
char a_string[20] = "This is a string";
printf("%d\n", a_string[16]); // returns 0 (as will byte 17-19) since the string only has chars initialized up to index 15

// MULTI-DIMENSIONAL ARRAYS

int multi_array[2][5] = {
    {1,2,3,4,5},
    {6,7,8,9,10}
};
multi_array[0][2]; // returns 3

// ---------- TYPE DEF ----------
    // typedef creates a type alias

typedef int my_type; // creates a type alias for int called my_type 
my_type wow_everyone_so_creative = 10; // declare and assigns an int value to a my_type variable

// ---------- STRUCT ----------
    // struct creates what is basically a javascript object
    // stores key-value pairs
    // note struct fields (attributes) are separated by semicolons, not commas

struct rectangle {
    int width;
    int height;
};

// INITALIZING STRUCT FIELDS

struct rectangle my_rect = {1,2}; // struct fields can be intialized immediately

// ACCESS STRUCT FIELDS
    // dot notation

my_rect.width; // returns 1
my_rect.height; // returns 20

// typedefs can be assigned to structs for convenience (and also can be done during struct definition)

typedef struct rectangle rect; // this is valid

int area(rect r) {
    return r.width * r.height;
}

typedef struct {
    int width;
    int height;
} rect; // this is also valid

Operators

// ---------- OPERATOR ----------

// ARITHMETIC

int i1 = 1, i2 = 2; // valid shorthand for multiple declaration
float f1 = 1.0, f2 = 2.0; // same here as well

i1 + i2; // addition
i1 - i2; // subtraction
i1 * i2; // multiplication
i1 / i2; // division, though in this case evaluates to 0.5 is truncated towards 0
11 % 3; // modulo, be careful when arguments are negative though

int j = 0;
int s = j++; // increment by 1 operator, returns j then increments it
int z = ++j; // increment by 1 operator, increments j then returns it
int e = j--; // decrement by 1 operator, decrements j then returns it
int f = --j; // decrement by 1 operator, decrements j then returns it

(float)i1/i2; // evaluates to 0.5f since we need to cast at least one integer to a float to get a floating-point result
i1/(double)i2; // does the same for doubles
f1 / f2; // evaluates to 0.5 since both are floats here so fulfills the above requirement of at least one operand being a float

// COMPARISON 

3 == 2; // complete equality in value and type, returns 0
3 != 2; // complete inequality in value and type, returns 1
3 > 2; // comparison operator, returns 1 
3 < 2; // comparison operator, returns 0
2 <= 2; // comparison operator, returns 1
2 >= 2; // comparison operator, returns 1

// LOGICAL

!3; // logical not, returns 0
0 && 1; // logical and, returns 0
0 || 1; // logical or, returns 1

Control structures

// ---------- CONTROL STRUCTURE ----------

// IF ELSE IF ELSE

int x = 5;
if (x > 5) {
    printf("x is bigger than 5\n");
} else if (x < 5) {
    printf("x is smaller than 5\n")
} else {
    printf("x is 5\n");
}

// LOOPS

// WHILE DO WHILE

int ii = 0;
while (ii < 10) {
    printf("%d, ", ii++); // recall that ii++ will increment ii after it retruns it, so this prints the string "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
}

int kk = 0; // do while loops exist too
do {
    printf("%d, ", kk);
} while (++k < 10);

// FOR

for (int jj = 0; jj < 10; jj++) {
    printf("%d, ", jj);
} // prints the string "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "

// SWITCH CASE 
    // remember to include break after each case, otherwise the logic falls through
    // default case exists

switch (a) {
    case 0:
        // do something
        break;
    case 1:
        // do something else:
        break;
    case 2:
        // do another thing
        break;
    default:
        // accounts for the default case like the catch-all operator _ in Rust
        break;
}

Functions

// ---------- CALL BY VALUE vs CALL BY REFERENCE ----------
    // CALL BY VALUE
        // a copy of the actual variable's value is called, so we are calling by value (how conventional functions with return values work)
    // CALL BY REFERENCE
        // the actual memory address of the variable is called and any changes are made to the variable itself, so we are calling by reference (how conventional object methods work)

// ---------- FUNCTION ----------
    // main function
    // function RETURN type specified at the front, followed by the function name and its arguments with their return types
    // functions are call by value by default, and a copy of the actual arguments are passed to a function (ie. the original argument values are not changed when the function is called) and a value has to be returned
    // pointers should be used if you want to edit the actual argument value
        // arrays are passed in as pointers by default
    // RETURN_TYPE FUNCTION_NAME(FUNCTION_ARGUMENTS_AND_TYPE);

int main(void) {
    // this is every C program's entry point, all C code must run within the main function
    return 0;
}

void function_1(); // you can declare a function ahead of time like this
int function_2(void); // or like this
int add_two_ints(int x1, int x2); // this is also valid function declaration

Pointers

// --------- POINTER ----------
    // pointer is a variable declared that stores a memory address
        // pointers variables are declared with * (once)
        // pointer declaration will also specify the type of the variable it points to
        // by convention, pointer variables are named p{variable name}
    // memory addressed of variables can be accessed and played with
        // memory addresses are accessed with &

int x = 0;
int *px = &x; // stores the memory address of int variable x in pointer variable px (subsequent reference to pointer variable px can be done without the *, that's used once on declaration only)

// DEREFERENCE A POINTER
    // to access the actual value at the memory address a pointer variable is pointing to, use the derefernce operator *
    // it is slightly confusing and odd that the dereference and declaration operator are the same, but just go with it

int value_at_px = *px; // evaluates to 0, the int value of variable x previously declared, and note how the * is not seen since that was only declared once on declaration
(*px)++; // changes the actual value of the variable stored at memory address stored in pointer variable px
printf("%d\n", *px); // prints 1, accessing the value stored at the memory address in the pointer variable px via the derefencing operator *
printf("%d\n", x); // this will also print 1

// ARRAYS AND POINTERS
    // in memory, an array is just a special chunk of memory that is reserved upon declaration with a fixed size
    // when pointing to an array, pointer variable points to the memory address of the first element of the array even without the & memory address accessing operator
    // this is as arrays are implictly type converted into a pointer (stores a memory address of the first element of the array) when they are assigned to functions or to a pointer variable

int x_array[3] = {1,2,3}; // declares and initializes an int array [1,2,3] of 12 bytes
int* px_array = x_array; // notice we don't need to use the & mem address accesing operator due to implicit type conversion of the array into its pointer (also known as decay)

// STRINGS AND POINTERS
    // strings are char arrays, but they can also be represented as a pointer to a char (pointer to the first element of the char array as established above)
    // this is done by convention, and should be practised as far as possible when creating const string literals 

const char *my_str = "This is my very own string literal"; // creates a string literal which should not be modified

char foo[] = "foo"; // this is valid if the length of the string or its contents are meant to be changed later on in writable memory
foo[0] = 'a'; // this is legal C code, char array foo variable now stores the char array "aoo" which is also represnted as {'a','o','o'}

// there are some exceptions to these rules, but in general they are as defined above

More on