More comments...

This commit is contained in:
Ognjen Milan Robovic 2023-11-09 15:43:14 -05:00
parent f1031f5360
commit 839f92f40f
2 changed files with 88 additions and 46 deletions

View File

@ -50,7 +50,7 @@ void echo (char * string) {
} }
void fatal_failure (int condition, char * message) { // We use this function to abort the program if condition is met and to print the message. void fatal_failure (int condition, char * message) { // We use this function to abort the program if condition is met and to print the message.
if (condition != 0) { // If the variable 'condition' is not equal to 0, we execute the code in curly braces. if (condition == FALSE) { // If the variable 'condition' is not equal to 0, we execute the code in curly braces.
echo ("[\033[1;31mExiting\033[0m] "); // Simply printing the message using our 'echo' function, but we also use some colours, more on that later. echo ("[\033[1;31mExiting\033[0m] "); // Simply printing the message using our 'echo' function, but we also use some colours, more on that later.
echo (message); // Also, notice how "this or that" is implicity 'char *' type... Maybe it's too early to explain it at this point. echo (message); // Also, notice how "this or that" is implicity 'char *' type... Maybe it's too early to explain it at this point.
echo ("\n"); // This will only print a new line, we'll see how to use it later. echo ("\n"); // This will only print a new line, we'll see how to use it later.
@ -82,7 +82,7 @@ char * data = NULL;
data = malloc (20 * sizeof (* data)); // Allocates 20 bytes of memory for 'data'. data = malloc (20 * sizeof (* data)); // Allocates 20 bytes of memory for 'data'.
data = calloc (20, sizeof (* data)); // Allocates 20 bytes also, but initializes them to 0 value. data = calloc (20, sizeof (* data)); // Allocates 20 bytes also, but initializes them to 0 value.
data = realloc (data, 20 * sizeof (* data)); // When 'data' is null pointer, it will be same as 'malloc', else it will reallocate more memory (for correct usage). data = realloc (data, 20 * sizeof (* data)); // When 'data' is null pointer, it will be same as 'malloc', else it will reallocate more memory (for correct usage).
// Also, it's best to just use 'calloc', but it complicates some other tasks.
free (data); // Deallocates memory, we'll talk about "double free" later. free (data); // Deallocates memory, we'll talk about "double free" later.
@ @
*/ */
@ -120,36 +120,79 @@ void * deallocate (void * data) {
return (NULL); return (NULL);
} }
/*
This program is intended to be a book-like guide for this source code, which is also a book. We'll deal with strings a lot, and they're a good example of code formatting which is
the main topic of chapter zero. In function 'string_length' we have for loop without a body, some people prefer to put '{}' or ';' in same or next line, to express the intention
that the loop shouldn't have a body (code block {}). I just put ';' on the same line. Also, functions 'string_*' could depend on functions 'string_*_limit', but we won't do that
now, and since we've already declared them in header file "chapter_0.h" we can define them and call them in whatever order we want. Nice.
@C
// Simple example of how we could make it dependable on 'string_*_limit' function...
int string_compare (char * string_0, char * string_1) {
return (string_0, string_1, string_length (string_0));
}
@
*/
int string_length (char * string) { int string_length (char * string) {
int length; int length;
if (string == NULL) { fatal_failure (string == NULL, "string_length: String is null pointer.");
return (0);
}
for (length = 0; string [length] != '\0'; ++length); for (length = 0; string [length] != CHARACTER_NULL; ++length); // Since in C, strings are null terminated, looping until we see null character is strings' length.
return (length); return (length);
} }
/*
Now, I've implemented "unlimited" versions of string comparison, copying and concatenation different from "limited" versions. They correspond with standard library functions
'strcmp', 'strcpy', 'strcat', 'strncmp', 'strncpy' and 'strncat' found in header file <string.h>. In "unlimited" versions, I rely on the fact that we want to apply the operation
on entire strings, that those strings are null terminated and I used that in my advantage. For example, function 'string_compare' could be something like this:
@C
int string_compare (char * string_0, char * string_1) { int string_compare (char * string_0, char * string_1) {
if (string_length (string_0) != string_length (string_1)) { int offset;
return (0);
} else { fatal_failure (string_0 == NULL, "string_compare: Destination string is null pointer.");
return (string_compare_limit (string_0, string_1, string_length (string_0))); fatal_failure (string_1 == NULL, "string_compare: Source string is null pointer.");
for (offset = 0; (string_0 [offset] != CHARACTER_NULL) && (string_1 [offset] != CHARACTER_NULL); ++offset) {
if (string_0 [offset] != string_1 [offset]) {
return (FALSE);
} }
} }
return (TRUE);
}
@
And I used this approach below to show that you can solve the problem using different solutions...
*/
int string_compare (char * string_0, char * string_1) {
fatal_failure (string_0 == NULL, "string_compare: Destination string is null pointer.");
fatal_failure (string_1 == NULL, "string_compare: Source string is null pointer.");
for (; (* string_0 != CHARACTER_NULL) && (* string_1 != CHARACTER_NULL); ++string_0, ++string_1) {
if (* string_0 != * string_1) {
return (FALSE);
}
}
return (TRUE);
}
char * string_copy (char * string_0, char * string_1) { char * string_copy (char * string_0, char * string_1) {
int i = 0;
fatal_failure (string_0 == NULL, "string_copy: Destination string is null pointer."); fatal_failure (string_0 == NULL, "string_copy: Destination string is null pointer.");
fatal_failure (string_1 == NULL, "string_copy: Source string is null pointer."); fatal_failure (string_1 == NULL, "string_copy: Source string is null pointer.");
for (i = 0; i != string_length (string_1) + 1; ++i) { for (; * string_1 != CHARACTER_NULL; ++string_0, ++string_1) {
string_0 [i] = string_1 [i]; * string_0 = * string_1;
} }
* string_0 = * string_1; // Copying null termination, since the loop stopped on that condition.
return (string_0); return (string_0);
} }
@ -159,66 +202,60 @@ char * string_concatenate (char * string_0, char * string_1) {
string_0 += string_length (string_0); string_0 += string_length (string_0);
while (* string_1 != '\0') { for (; * string_1 != CHARACTER_NULL; ++string_0, ++string_1) {
* string_0++ = * string_1++; * string_0 = * string_1;
/*++string_0;
++string_1;*/
} }
* string_0 = '\0'; * string_0 = CHARACTER_NULL;
return (string_0); return (string_0);
} }
int string_compare_limit (char * string_0, char * string_1, int limit) { int string_compare_limit (char * string_0, char * string_1, int limit) {
int i = 0; int offset;
fatal_failure (string_0 == NULL, "string_compare_limit: Destination string is null pointer."); fatal_failure (string_0 == NULL, "string_compare_limit: Destination string is null pointer.");
fatal_failure (string_1 == NULL, "string_compare_limit: Source string is null pointer."); fatal_failure (string_1 == NULL, "string_compare_limit: Source string is null pointer.");
for (i = 0; i != limit; ++i) { for (offset = 0; offset != limit; ++offset) {
if (string_0 [i] != string_1 [i]) { if (string_0 [offset] != string_1 [offset]) {
return (0); return (FALSE);
} }
} }
return (1); return (TRUE);
} }
char * string_copy_limit (char * string_0, char * string_1, int limit) { char * string_copy_limit (char * string_0, char * string_1, int limit) {
int i = 0; int offset;
fatal_failure (string_0 == NULL, "string_copy_limit: Destination string is null pointer."); fatal_failure (string_0 == NULL, "string_copy_limit: Destination string is null pointer.");
fatal_failure (string_1 == NULL, "string_copy_limit: Source string is null pointer.");
if (limit <= 0) { if ((limit <= 0) || (string_1 == NULL)) {
return (string_0); return (string_0);
} }
for (i = 0; i != limit; ++i) { for (offset = 0; offset != limit; ++offset) {
string_0 [i] = string_1 [i]; string_0 [offset] = string_1 [offset];
} }
return (string_0); return (string_0);
} }
char * string_concatenate_limit (char * string_0, char * string_1, int limit) { char * string_concatenate_limit (char * string_0, char * string_1, int limit) {
int i = 0; int offset, length_0, length_1;
int length_0 = 0;
int length_1 = 0;
fatal_failure (string_0 == NULL, "string_concatenate_limit: Destination string is null pointer."); fatal_failure (string_0 == NULL, "string_concatenate_limit: Destination string is null pointer.");
fatal_failure (string_1 == NULL, "string_concatenate_limit: Source string is null pointer.");
if (limit <= 0) { if ((limit <= 0) || (string_1 == NULL)) {
return (string_0); return (string_0);
} }
length_0 = string_length (string_0); length_0 = string_length (string_0);
length_1 = string_length (string_1); length_1 = string_length (string_1);
for (i = 0; (i != length_1) && (i != limit); ++i) { for (offset = 0; (offset != length_1) && (offset != limit); ++offset) {
string_0 [length_0 + i] = string_1 [i]; string_0 [length_0 + offset] = string_1 [offset];
} }
return (string_0); return (string_0);

View File

@ -167,14 +167,9 @@ eye on how are they aligned and named. I'll reimplement some standard functions,
#define SIGNAL_ARROW_RIGHT (0X435B1B) #define SIGNAL_ARROW_RIGHT (0X435B1B)
#define SIGNAL_ARROW_LEFT (0X445B1B) #define SIGNAL_ARROW_LEFT (0X445B1B)
enum { // I like to align enumerations with 10, 20 or 40 characters per name, and optionally use NAME_ as prefix and NAME_COUNT as last element. enum { // This is completely unnecesary, but I don't care, it's a good showcase how boolean type can work, true is 1 and false is 0.
EFFECT_NORMAL, EFFECT_BOLD, EFFECT_ITALIC, EFFECT_UNDERLINE, EFFECT_BLINK, EFFECT_REVERSE, FALSE,
EFFECT_COUNT TRUE
};
enum { // Because of text auto-completition, it's always easy to find what I want, or to use NAME_COUNT in arrays. In some cases, order matters!
COLOUR_GREY, COLOUR_RED, COLOUR_GREEN, COLOUR_YELLOW, COLOUR_BLUE, COLOUR_PINK, COLOUR_CYAN, COLOUR_WHITE,
COLOUR_COUNT
}; };
enum { // This is also one of my preferences, to use CHARACTER_NULL or CHARACTER_LINE_FEED instead of '\0' or '\n' in special (non-string) cases. enum { // This is also one of my preferences, to use CHARACTER_NULL or CHARACTER_LINE_FEED instead of '\0' or '\n' in special (non-string) cases.
@ -189,6 +184,16 @@ enum { // This is also one of my preferences, to use CHARACTER_NULL or CHARACTER
CHARACTER_COUNT CHARACTER_COUNT
}; };
enum { // I like to align enumerations with 10, 20 or 40 characters per name, and optionally use NAME_ as prefix and NAME_COUNT as last element.
EFFECT_NORMAL, EFFECT_BOLD, EFFECT_ITALIC, EFFECT_UNDERLINE, EFFECT_BLINK, EFFECT_REVERSE,
EFFECT_COUNT
};
enum { // Because of text auto-completition, it's always easy to find what I want, or to use NAME_COUNT in arrays. In some cases, order matters!
COLOUR_GREY, COLOUR_RED, COLOUR_GREEN, COLOUR_YELLOW, COLOUR_BLUE, COLOUR_PINK, COLOUR_CYAN, COLOUR_WHITE,
COLOUR_COUNT
};
extern void in (void * data, int size); // We'll use these functions later as core standard input/output functions. extern void in (void * data, int size); // We'll use these functions later as core standard input/output functions.
extern void out (void * data, int size); extern void out (void * data, int size);