// A simple example of strings in C
// Illustrates:
//      All kinds of mischief
//      strings are allocated sequentially
//      array indices are NOT checked
//      can access memory outside of an array
//      opens the door for all kinds of errors
//
// Compile: gcc errorstrings.c
// Run: a.out
// Optional Compile: gcc -o errorstrings errorstrings.c
// Optional Run: errorstrings

#include <stdio.h>

int main()
{
    // Local variables are allocated from high to low addresses
    int i;
    int ohno;
    char aStr2[] = "EFG"; // Notice: No 'D'
    char aStr1[] = "ABC";

    printf("String variable aStr1: '%s'\n", aStr1);
    printf("String variable aStr2: '%s'\n", aStr2);

    // Print EIGHT characters
    for (i=0; i < 8; i++)
    {
        printf("Character %d, decimal, hex, and character: %d, %x, '%c'\n",
                i, aStr1[i], aStr1[i], aStr1[i]);
    }
    printf("\n");  // Print a blank line
    
    aStr1[3] = 'D';  // No array bounds checking! Yikes!

    printf("aStr1 as string: '%s'\n", aStr1); // aStr1 as string: 'ABCDEFG'
    printf("aStr2 as string: '%s'\n", aStr2); // aStr2 as string: 'EFG'
    printf("\n");  

    for (i=0; i < 8; i++)
    {
        printf("Character %d, decimal, hex, and character: %d, %x, '%c'\n",
                i, aStr1[i], aStr1[i], aStr1[i]);
    }
    printf("\n");  

    // No type checking and no array bounds checks!
    aStr1[5] = 76;    // What characters have values 75 and 76?
    aStr2[-3] = 75;   // Where do these values go?
    printf("String variable aStr1: '%s'\n", aStr1);
    printf("String variable aStr2: '%s'\n", aStr2);
    printf("\n");

    ohno = 0;
    printf("Ohno before: %d\n", ohno);
    aStr2[4] = 1;  // Ouch!
    printf("Ohno after: %d, %c\n", ohno, ohno);
    aStr2[4] = 'a';  // Ouch!
    printf("Ohno after: %d, %c\n", ohno, ohno);

    // For strings, printf expects addresses, and so we must pass ohno's address
    printf("Ohno after: %d, %c, %s\n", ohno, ohno, &ohno);

    // Access values above aStr1 on the stack
    printf("astr[-1]: %d, %c\n", aStr1[-1], aStr1[-1]);
    aStr1[-1] = 'a';  // Ouch!
    printf("astr[-1]: %d, %c\n", aStr1[-1], aStr1[-1]);
}

/* Output (when run on rucs):
String variable aStr1: 'ABC'
String variable aStr2: 'EFG'
Character 0, decimal, hex, and character: 65, 41, 'A'
Character 1, decimal, hex, and character: 66, 42, 'B'
Character 2, decimal, hex, and character: 67, 43, 'C'
Character 3, decimal, hex, and character: 0, 0, '^@'
Character 4, decimal, hex, and character: 69, 45, 'E'
Character 5, decimal, hex, and character: 70, 46, 'F'
Character 6, decimal, hex, and character: 71, 47, 'G'
Character 7, decimal, hex, and character: 0, 0, '^@'

aStr1 as string: 'ABCDEFG'
aStr2 as string: 'EFG'

Character 0, decimal, hex, and character: 65, 41, 'A'
Character 1, decimal, hex, and character: 66, 42, 'B'
Character 2, decimal, hex, and character: 67, 43, 'C'
Character 3, decimal, hex, and character: 68, 44, 'D'
Character 4, decimal, hex, and character: 69, 45, 'E'
Character 5, decimal, hex, and character: 70, 46, 'F'
Character 6, decimal, hex, and character: 71, 47, 'G'
Character 7, decimal, hex, and character: 0, 0, '^@'

String variable aStr1: 'AKCDELG'
String variable aStr2: 'ELG'

Ohno before: 0
Ohno after: 1, ^A
Ohno after: 97, a
Ohno after: 97, a, a
astr[-1]: 0, ^@
astr[-1]: 97, a
*/