Sfoglia il codice sorgente

Very tiny text added...

master
parent
commit
755d47d478
4 ha cambiato i file con 36 aggiunte e 27 eliminazioni
  1. +28
    -19
      chapters/chapter_0.c
  2. +3
    -3
      chapters/chapter_0.h
  3. +4
    -4
      compile.sh
  4. +1
    -1
      xhartae.c

+ 28
- 19
chapters/chapter_0.c Vedi 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.
if (condition == FALSE) { // If the variable 'condition' is not equal to 0, we execute the code in curly braces.
if (condition == TRUE) { // 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 (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.
@@ -167,57 +167,64 @@ int string_compare (char * string_0, char * string_1) {
}
@

And I used this approach below to show that you can solve the problem using different solutions...
And I used this approach below to show that you can solve the problem using different solutions... You'll notice that "limited" versions have variable 'offset' of type integer. We
use it to interate the strings, while in "unlimited" versions, we iterate on pointers to those strings, which are pushed to the stack. Both versions work, both versions give the
same results, you can use any of them.
*/

int string_compare (char * string_0, char * string_1) {
fatal_failure (string_0 == NULL, "string_compare: Destination string is null pointer.");
fatal_failure (string_0 == NULL, "string_compare: Destination string is null pointer."); // This will be seen in next 5 functions too, we don't want NULL here.
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);
for (; (* string_0 != CHARACTER_NULL) && (* string_1 != CHARACTER_NULL); ++string_0, ++string_1) { // We iterate until either string reaches the null character.
if (* string_0 != * string_1) { // In case that characters at the same offset are different:
return (FALSE); // > We return FALSE, 0, since strings aren't the same...
}
}

return (TRUE);
return (TRUE); // Otherwise, strings are same, we return TRUE, 1.
}

char * string_copy (char * string_0, char * string_1) {
fatal_failure (string_0 == NULL, "string_copy: Destination string is null pointer.");
fatal_failure (string_1 == NULL, "string_copy: Source string is null pointer.");

for (; * string_1 != CHARACTER_NULL; ++string_0, ++string_1) {
* string_0 = * string_1;
for (; * string_1 != CHARACTER_NULL; ++string_0, ++string_1) { // This time and in next function, we iterate only source string.
* string_0 = * string_1; // And we assign character at the same offset to destination string (aka copy it).
}

* string_0 = * string_1; // Copying null termination, since the loop stopped on that condition.
* string_0 = * string_1; // Copying null termination, since the loop stopped on that condition.

return (string_0);
return (string_0); // Lastly, we return the destination string, in order to be able to bind functions.
}

char * string_concatenate (char * string_0, char * string_1) {
fatal_failure (string_0 == NULL, "string_concatenate: Destination string is null pointer.");
fatal_failure (string_1 == NULL, "string_concatenate: Source string is null pointer.");

string_0 += string_length (string_0);
for (; * string_1 != CHARACTER_NULL; ++string_0, ++string_1) {
* string_0 = * string_1;
string_0 += string_length (string_0); // We'll first offset destination string to the end of it.
// Because we want to start copying from the end, aka concatenate it.
for (; * string_1 != CHARACTER_NULL; ++string_0, ++string_1) { // The rest of the function is same as string_copy, so:
* string_0 = * string_1; // We could even use it here, but that defies the purpose of learning now.
}

* string_0 = CHARACTER_NULL;
* string_0 = CHARACTER_NULL; // Again, assign null termination.

return (string_0);
}

/*
As for "limited" versions of previous 3 functions, they do the same thing, but are capped to some variable 'limit'. These functions have their own use-case, for example, if
strings aren't null terminated, if you're not sure that they are null terminated, if we're dealing with binary (not textual) data (casted to char *), and many more cases.
*/

int string_compare_limit (char * string_0, char * string_1, int limit) {
int offset;

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.");

for (offset = 0; offset != limit; ++offset) {
for (offset = 0; offset < limit; ++offset) {
if (string_0 [offset] != string_1 [offset]) {
return (FALSE);
}
@@ -230,12 +237,13 @@ char * string_copy_limit (char * string_0, char * string_1, int limit) {
int offset;

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) || (string_1 == NULL)) {
return (string_0);
}

for (offset = 0; offset != limit; ++offset) {
for (offset = 0; offset < limit; ++offset) {
string_0 [offset] = string_1 [offset];
}

@@ -246,6 +254,7 @@ char * string_concatenate_limit (char * string_0, char * string_1, int limit) {
int offset, length_0, length_1;

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) || (string_1 == NULL)) {
return (string_0);
@@ -254,7 +263,7 @@ char * string_concatenate_limit (char * string_0, char * string_1, int limit) {
length_0 = string_length (string_0);
length_1 = string_length (string_1);

for (offset = 0; (offset != length_1) && (offset != limit); ++offset) {
for (offset = 0; (offset < length_1) && (offset < limit); ++offset) {
string_0 [length_0 + offset] = string_1 [offset];
}



+ 3
- 3
chapters/chapter_0.h Vedi File

@@ -181,7 +181,7 @@ enum { // This is also one of my preferences, to use CHARACTER_NULL or CHARACTER
CHARACTER_DEVICE_CONTROL_4, CHARACTER_NOT_ACKNOWLEDGE, CHARACTER_SYNCHRONOUS_IDLE, CHARACTER_END_TRANSMISSION_BLOCK,
CHARACTER_CANCEL, CHARACTER_END_MEDIUM, CHARACTER_SUBSTITUTE, CHARACTER_ESCAPE,
CHARACTER_FILE_SEPARATOR, CHARACTER_GROUP_SEPARATOR, CHARACTER_RECORD_SEPARATOR, CHARACTER_UNIT_SEPARATOR,
CHARACTER_COUNT
CHARACTER_COUNT // Not an actual ASCII table count (128), but for starting invisible characters.
};

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.
@@ -209,11 +209,11 @@ extern void * deallocate (void * data );

extern int string_length (char * string); // We deal with strings a lot in this program, so string functions will be more important than character functions from chapter one.

extern int string_compare (char * string_0, char * string_1);
extern int string_compare (char * string_0, char * string_1); // See how nicely they align, right?
extern char * string_copy (char * string_0, char * string_1);
extern char * string_concatenate (char * string_0, char * string_1);

extern int string_compare_limit (char * string_0, char * string_1, int limit);
extern int string_compare_limit (char * string_0, char * string_1, int limit); // These ones too, it's beautiful (in my opinion), tho some consider it useless.
extern char * string_copy_limit (char * string_0, char * string_1, int limit);
extern char * string_concatenate_limit (char * string_0, char * string_1, int limit);



+ 4
- 4
compile.sh Vedi File

@@ -2,11 +2,11 @@

set -xe

gcc -Wall -Wextra -Wpedantic -Werror -Ofast -c -o chapters/chapter_0.o chapters/chapter_0.c
gcc -Wall -Wextra -Wpedantic -Werror -Ofast -c -o chapters/chapter_1.o chapters/chapter_1.c
gcc -Wall -Wextra -Wpedantic -Werror -Ofast -c -o chapters/chapter_2.o chapters/chapter_2.c
gcc -g -Wall -Wextra -Wpedantic -Werror -O0 -c -o chapters/chapter_0.o chapters/chapter_0.c
gcc -g -Wall -Wextra -Wpedantic -Werror -O0 -c -o chapters/chapter_1.o chapters/chapter_1.c
gcc -g -Wall -Wextra -Wpedantic -Werror -O0 -c -o chapters/chapter_2.o chapters/chapter_2.c

gcc -Wall -Wextra -Wpedantic -Werror -Ofast -c -o xhartae.o xhartae.c
gcc -g -Wall -Wextra -Wpedantic -Werror -O0 -c -o xhartae.o xhartae.c

gcc -o xhartae xhartae.o chapters/chapter_0.o chapters/chapter_1.o chapters/chapter_2.o



+ 1
- 1
xhartae.c Vedi File

@@ -29,7 +29,7 @@ Why should you learn or use C programming language in 2023?
- C can interface with huge variety of other distinct programming languages.
- C can be a lot more readable, faster and easier if used well.

One sane C program should have the following structure:
One sane C program should have the following structure (please keep in mind that this is a book, not a sane program, thanks...):

0) Optional file, author or license information in comment.
1) Header guards and implementation definitions.


Loading…
Annulla
Salva