Programming/C/Syntax: Difference between revisions

From Dev Wiki
< Programming‎ | C
Jump to navigation Jump to search
(Create page)
 
m (Brodriguez moved page C/Syntax to Programming/C/Syntax)
 

Latest revision as of 03:57, 21 April 2023

Comments

Inline Comments

// This is an inline comment.

Block Comments

/**
 * This is a block comment.
 * Comment line 2.
 * Another block comment line.
 */


Variables


Pointers

Unlike most other languages, C gives access to pointers.
A "pointer" is effectively "the memory address of the respective variable".

In short:

  • & - If put before a variable, will give the memory address the variable resides at.
  • * - If put before a variable, will interpret as a memory address and give the value residing at said location.

Pointer Explanation

The purpose of a pointer is to simplify data in memory being passed around.
That is, if you have a large data structure, rather than copying or moving that data structure around (as you call functions, etc), it can be cheaper/easier to just pass the memory address that the data structure exists at.

In all the following examples, we use integers, but the same logic applies to every data type there is.

For example, we may have this:

// Declare our int.
int my_int_var = 5;

// Get pointer to variable.
int* my_int_ptr = &my_int_var;

// Change variable value, using pointer.
my_int_ptr* = 10

When we pass the above pointer around, we are telling our program "this is the memory address to look for our integer".
We can then use the pointer to reference our original value with the following:

// Print out pointer.
printf("Value for "my_int_var" is %i\n", *my_inv_ptr);

// Print out direct value. This will give the same as our pointer.
printf("Value for "my_int_var" is %i\n", my_inv_var);

Finally, note that we can have pointers to pointers. So still referring to the above code, we may have:

// Create pointer to pointer.
int* my_int_ptr2 = &my_int_ptr;

// Print out direct value. This will give the same as our pointer.
printf("Value for "my_int_var" is %i\n", **my_inv_ptr2);

Note that there is no limit to how deep pointers can nest. So it's possible to have pointers to pointers to pointers to....for infinity.

Malloc & Calloc

Sometimes, a programmer will know they'll need a pointer in the future, without having a value yet. Such as maybe getting input from a user.

In such cases, we can use the malloc() and calloc() functions. These two both allocate memory, but calloc() will set the associated memory bits to "0" on allocation.

Note that any time malloc or calloc is used, the free() function should be called once the variable is no longer in use. Otherwise, memory leaks will occur as the program runs.

Malloc Example:

// Create pointer with malloc.
int* my_value = malloc(1 * sizeof(int));

// Free pointer (to prevent memory leaks).
free(my_value);

Calloc Example:

 // Create pointer with malloc.
int* my_value = calloc(1, sizeof(int));

// Free pointer (to prevent memory leaks).
free(my_value);

In both instances, note that we specify both the size of each object, and the number of objects to reference. In both cases, we are saying "I want a pointer to exactly one integer".

If we instead want "a pointer to memory that contains 10 different integers", then we can instead have the following:

// Create pointer with malloc.
int* my_value = calloc(10, sizeof(int));

// Reference, say, the 5th integer in our set.
my_value[5] = 10;

// Free pointer (to prevent memory leaks).
free(my_value);

Why Have Nested Pointers

Given the above examples, pointers can be thought of in two ways: 1) A pointer can be thought of as a reference to a memory address. 2) A pointer can be thought of as a reference to an array.

So theoretically, with if you need a "a pointer to an array"? Or if you need "an array that contains pointers"? Or even just a "multi-dimensional array (2d, 3d, etc)"?

In these cases, we would want to have nested pointers, to suite our needs.

Note: For all three of the below examples, the syntax to reference values is still the same "nested pointer" syntax. The only thing that changes is how you should mentally imagine the data structure.

For example, a pointer to an array may look like:

// Create array of 20 ints, via pointer syntax.
int* my_array = calloc(20, sizeof(int));

// Create pointer to array.
int** arr_pointer = &my_array;

If we wanted an array of pointers, then we might have:

// Create array with 20 different int pointers.
int** my_array = calloc(20, sizeof(int*));

// Create associated pointers.
for (int index = 0; index < 20; index++) {
    my_array[index] = calloc(1, sizeof(int*));
}

If we wanted a 2-D array, then we could use pointer syntax to have:

// Create array with 20 different 1-D rows.
int** my_array = calloc(20, sizeof(int*));

// Loop through and create associated rows.
for (int index = 0; index < 20; index++) {
    // Each 1-D row can be whatever size we want. In this case, 10 values long.
    my_array[index] = calloc(10, sizeof(int));
}

If Statements

Loops

Functions