1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | #include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
char* make_asterisks_string(int num_asterisks) {
char* asterisks = malloc(sizeof(*asterisks) * (num_asterisks + 1));
// Declare 'asterisks' as type char* (address of a char) and initialize it to the address of a
// newly allocated buffer on the HEAP segment where we will store the asterisks and the
// null terminator ('\0').
//
// ∙ malloc(sizeof(*asterisks) * (num_asterisks + 1)) allocates a buffer on the HEAP segment
// sufficient to store 'num_asterisks' asterisks and the null terminator.
//
// ∙ sizeof(*asterisks) is the number of bytes needed to store ONE object of the same
// type as (*asterisks).
// ∘ asterisks is a char* because it was declared that way.
// ∘ *asterisks is a char because adding a '*' to an expression removes an '*' from its type.
// ∘ sizeof(*asterisks) is the same as sizeof(char), but we always use sizeof(«expression»),
// not sizeof(«type»).
// ∘ sizeof(*asterisks) is the number of bytes needed to store a char on our platform.
// ∘ sizeof(*asterisks) * (num_asterisks + 1) is the number of bytes needed to store
// (num_asterisks + 1) char's on our platform. In other words, it is the number of bytes
// needed to store the whole string of asterisks, plus the null terminator ('\0').
//
// ∙ "Buffer" just means an area of memory. Most of the time, we can think of it as an array.
// We use the word "buffer" because there will be times later when we allocate space on the
// heap for something other than an array, such as an int or a struct object (covered soon).
//
//
// PITFALLS
//
// ∙ DO NOT FORGET THE ASTERISK!!!
// ∘ GOOD: ▒▒▒ = malloc(sizeof(*asterisk) * ▒▒▒)
// ▲
// └─IMPORTANT!!!
// ∘ BAD!: ▒▒▒ = malloc(sizeof( asterisk) * ▒▒▒)
// ▲
// └─Missing - will cause problems
//
// ∙ Always use sizeof(«EXPRESSION»), -NOT- sizeof(«TYPE»)
// ∘ GOOD: ▒▒▒ = malloc(sizeof(*asterisk) * ▒▒▒)
// ∘ BAD!: ▒▒▒ = malloc(sizeof(char) * ▒▒▒)
//
// ∙ Do not add a typecast // ex: char* asterisks = (char*) malloc(…).
// ∘ GOOD: ▒▒▒ = malloc(sizeof(*asterisk) * ▒▒▒)
// ∘ BAD: ▒▒▒ = (char*)malloc(sizeof(*asterisk) * ▒▒▒)
// └──┬──┘
// BAD!
//_________________________________________________
// At this point, 'address' contains the address of our newly allocated buffer (area in memory).
// However, that buffer has not been initialized. Until we write some bytes (characters in this
// case), we cannot predict what will be in that memory.
//
// Fill the buffer at address 'asterisks' with the asterisks, plus the null terminator ('\0').
// In programming lingo, this is sometimes called "populating the array".
for(int i = 0; i < num_asterisks; i++) {
asterisks[i] = '*';
}
asterisks[num_asterisks] = '\0'; // REMEMBER!!!! Add the null terminator.
// If we didn't write the '\0' after the last asterisk, then when we printed the string of
// asterisks, we *might* get some additional junk after the asterisks. We can't predict what
// will be in memory until it has been initialized (assigned a value for the first time).
// IMPORTANT: The buffer on the heap segment will still be allocated (i.e., usable by us) even
// after the function returns.
return asterisks;
// Return the address of the newly allocated buffer on the heap.
}
int main(int argc, char* argv[]) {
char* asterisks = make_asterisks_string(7);
// 'asterisks' now contains the address of a buffer containing the string "*******" including
// the null terminator.
printf("asterisks == \"%s\"\n", asterisks);
// Output:
// asterisks == "*******"
// IMPORTANT: For every call to malloc(…), we must call free(…) with the address that malloc(…)
// returned. Otherwise, you will have a memory leak. (Memory leaks will be covered next week.)
free(asterisks);
return EXIT_SUCCESS;
}
/* vim: set tabstop=4 shiftwidth=4 fileencoding=utf-8 noexpandtab: */
|
© Copyright 2023 Alexander J. Quinn This content is protected and may not be shared, uploaded, or distributed.