Key Notes for C Language Programming Practice and Interviews
A compiler targeting N-bit architecture uses N bits to store a single pointer. A 16-bit architecture uses 2 bytes for an int type, and (2^{10} = 1024).
Operator Precedence & Associativity
Assignment operators such as += and = follow right-to-left associativity. For example, a += 1 expands to a = a + 1: the right-hand expression a + 1 is evaluated first, then the result is assigned to the left-hand variable, which matches the behavior of right-to-left asssociativity.
printf Formatting Rules
For formatted output, the specifier %6.9s sets a minimum output width of 6 characters and a maximum output length of 9 characters.
Comma Expressions
Comma expressions evaluate every operand from left to right, and the overall result of the expression is the value of the last operand. For example, the result of (val_a = 5, val_b = 2, val_a > val_b ? val_a++ : val_b++, val_a + val_b) is equal to the value of val_a + val_b after all preceding operations complete.
sizeof vs strlen
sizeof calculates the total number of bytes occupied by a type or value, including the trailing null terminator \0 for strings. strlen only counts the number of visible characters, and does not include the trailing \0 in its result.
Formatting Differences Between printf and scanf
float input_num = 3.14159;
printf("%3.2f\n", input_num);
// 3 = minimum total output width, 2 = number of decimal places to retain (precision)
scanf only supports configuration of maximum input width, and does not support precision configuration. When reading multiple values with scanf, separate inputs with spaces or newlines to distinguish them:
int x, y;
scanf("%d%d", &x, &y);
Arrays
In C99 and later standards, array length can be specified with a variable (for variable-length arrays), it is not required to be a compile-time constant.
C++ Class Object Size Rules
- An empty class occupies 1 byte of memory
- Non-virtual member functions do not contribute to the size of a class instance
- A class with at least one virtual function stores a virtual table pointer: 4 bytes on 32-bit systems, 8 bytes on 64-bit systems
sizeof(void*)= 4 bytes on 32-bit systemssizeof(void)is undefined in standard C/C++, though some compilers return 1 byte as a special case- Static class members are shared across all instances and not stored in individual class objects, so they do not contribute to
sizeofresults
2D Array Pointer Arithmetic
For a 2D array int data[3][4];:
- Both
dataanddata[0]point to the first element of the array data[0]is the address ofdata[0][0]data[1]is the address of the first element of the second row,data[2]is the address of the first element of the third row.data[1] + 1points to the second element on the second rowdataitself is the address of the 0th row.data + iis the address of the ith row,*(data + i)is the address of the 0th column of the ith row, and*(data + i) + jis equivalent to&data[i][j]&datais the address of the entire 2D array.&data + 1skips the entire array, moving the adress forward by 12intunits (the full size of the array in this example)
Pointer Arithmetic
If you have a pointer double *p, p + 1 moves the pointer forward by sizeof(double) = 8 bytes, regardless of system bitness.
Parameter Passing for Modifying Values
To modify the value of a non-pointer variable enside a called function, you need to pass a first-level pointer to the variable. To modify the value of a first-level pointer itself (for example, changing the address it points to), you need to pass a second-level pointer.
XOR Operation
XOR, written as ^ in C, follows the rule: matching bits produce 0, different bits produce 1. This gives us the base results: 0^0 = 0, 1^0 = 1, 0^1 = 1, 1^1 = 0. An example of XOR assignment is output ^= i % 3.
Character vs String Constants
- Character constants can be modified, and participate in numeric operations using their ASCII value converted to an integer
- String constants are stored in read-only memory and cannot be modified. To work with a modifiable string, store it in a character array instead of pointing directly to the constant string
Example of illegal modification:
const char *greeting = "Hello";
greeting[0] = 'h'; // Illegal: cannot modify read-only string constant content
Modifiable string example (uses character array):
char greeting_arr[] = "Hello, World!";
Character Pointers vs Character Arrays
// String stored in read-only static memory, cannot modify content
char *text = "string";
const char *const_text = "abcdef";
// All three declarations below create equivalent modifiable character arrays
char arr_a[] = "abc";
char arr_b[] = {"abc"};
char arr_c[] = {'a', 'b', 'c', '\0'};
// This is fully legal: we can modify individual elements of the array
arr_a[0] = 'X';
Endianness
- Low address = address with a smaller numeric value, high address = address with a larger numeric value
- Little-endian mode: The lowest-order byte of data is stored at the lowest memory address, and the highest-order byte is stored at the highest memory address
Common ASCII Values
- Lowercase
a: 97,b: 98 - Uppercase
A: 65