Day 70: Printing Array Addresses in C

To better understand how to manipulate array pointers I tried to take my previous copy line program and add output for each address in the character arrays. It went well but there is a bug at the end of my copied string which has me concerned. It is misaligned and has an extra element which makes me wonder why that is happening in the copy and not in the initial string.

TLDR;

Okay, so here are the highlights of what I did:

  • Continued to work on the “Technical Questions” section of the book “Cracking the Coding Interview” by Gayle Laakmann McDowell. Within that, I continued my work on Tree data structures. Started trying to replicate the example pretty print functions provided in the article I am reading through. I covered enums in C and how to construct enumerations. The syntax was a little confusing at first but I finally got it. I took a ton of notes which you can see below. They aren’t perfect but they helped me make sense of it all at least. I also modified my “copy line” program to add the array element addresses as an additional output. It went somewhat well but I have some questions on the last element in the copied string array.

C Modified Copy string Program

/*
 * This program will take an existing string (char array) 
 * and copy it into a new string (char array).
 *
 * This program will also print out the corresponding 
 * addresses for each character array element 
 *
 * */

#include <stdlib.h>
#include <stdio.h>

int main(){
  char charString[] = "Hello World";
  char charStringCopy[12];

  char* charPtr;
  char* copyCharPtr;

  charPtr = charString;            // Pointer is assigned to the address of the first element in the array
  copyCharPtr = charStringCopy;    // Pointer is assigned to the address of the first element in the array

  //printf("String value pointed by pointer is: %s\n", *charPtr);

  int i = 0;
  while(*charPtr != '\0'){
    printf("Original String: %c\tAddress: %d\tArray Index: %i\n", *charPtr, charPtr, i++);        // Displays the value pointed at by the pointer.
    *copyCharPtr++ = *charPtr++;    // Copies the value pointed at by charPtr into address pointed at by copyCharPtr
                                    // Then increments the address stored in each pointer by one to access the next element in the string
  }

  *copyCharPtr = '\0';
  //printf("\n\nNew copied string pointer is: %s\n", *copyCharPtr);
  //puts(charStringCopy);

  printf("\n");
  copyCharPtr -= i+1;
  i = 0;
  while(*copyCharPtr != '\0'){
    printf("Copied String: %c\tAddress: %d\tArray Index: %i\n", *copyCharPtr, copyCharPtr++, i++);
  }

  return 0;
}
# Output

Original String: H      Address: 6422296        Array Index: 0
Original String: e      Address: 6422297        Array Index: 1
Original String: l      Address: 6422298        Array Index: 2
Original String: l      Address: 6422299        Array Index: 3
Original String: o      Address: 6422300        Array Index: 4
Original String:        Address: 6422301        Array Index: 5
Original String: W      Address: 6422302        Array Index: 6
Original String: o      Address: 6422303        Array Index: 7
Original String: r      Address: 6422304        Array Index: 8
Original String: l      Address: 6422305        Array Index: 9
Original String: d      Address: 6422306        Array Index: 10

Copied String: H        Address: 6422283        Array Index: 0
Copied String: e        Address: 6422284        Array Index: 1
Copied String: l        Address: 6422285        Array Index: 2
Copied String: l        Address: 6422286        Array Index: 3
Copied String: o        Address: 6422287        Array Index: 4
Copied String:          Address: 6422288        Array Index: 5
Copied String: W        Address: 6422289        Array Index: 6
Copied String: o        Address: 6422290        Array Index: 7
Copied String: r        Address: 6422291        Array Index: 8
Copied String: l        Address: 6422292        Array Index: 9
Copied String: d        Address: 6422293        Array Index: 10
Copied String:  Address: 6422294        Array Index: 11

Notes on enum data type in C

An enumeration consists of a set of named integer constants. An enumeration type declaration gives the name of the (optional) enumeration tag/identifier. It defines the set of named integer identifiers (called the enumeration setenumerator constantsenumerators, or members). A variable of the enumeration type stores one of the values of the enumeration set defined by that type.

Variables of enum type can be used in indexing expressions and as operands of all arithmetic and relational operators. Enumerations provide an alternative to the #define preprocessor directive with the advantages that the values can be generated for you and obey normal scoping rules.

In ANSI C, the expressions that define the value of an enumerator constant always have int type. That means the storage associated with an enumeration variable is the storage required for a single int value. An enumeration constant or a value of enumerated type can be used anywhere the C language permits an integer expression.

// Syntax

// Enumeration type declaration syntax:
 enum identifier(optional) { enumerator-list }
 enum identifier

// Enumerator list syntax:
 enumerator
 enumerator-list, ... , enumerator

// Enumerator syntax:
 enumeration-constant
 enumeration-constant = constant-expression(int value)

// Enumeration-constant syntax:
 identifier(i.e. constant variable name)

The optional identifier names the enumeration type defined by enumerator-list. This identifier is often called the “tag” of the enumeration specified by the list. When declaring variables that will hold a value of this enumeration type we will use both enum and the identifier to associated the created type with the enumerator-list Here is an example:

enum identifier {
  // enumeration-list
}

enum identifier variable_name;    // Declare a variable of the constructed enum type.

The integer constant value assigned to each enumeration-constant in the list can be assigned a constant integer value or by default have an auto-incremented value assigned to each of them. The auto-incrementation starts at the first value holding 0, then 1, then 2, etc… until the end of the enumeration-list. The same value can be assigned to multiple enumeration-constants in the same list.

Because enumaration-constants are still constants, there can only be one unique constant-expression per program. If two different enumerator-lists contains the same constant-expression, the compiler will give us an error. For example, this code will give us an error.

#include <stdio.h>

enum bool {false, true};

// Causes an error (Cannot re-declare a constant)
enum bool2 {false, true} false2, true2;

enum bool3 {F, T} false3, true3;

Also, by default all declared but uninitialized enum variables receive a default value of 0 not the first enumeration-constant in the enumator-list.

Also the auto-incrementation for undeclared enumeration-constant values starts from the last value assigned or 0 by defualt. It doesn’t start where it last left off. I think?? There are more things that I need to test out but for now I have a decent enough understanding to move forward.

Enumeration Type Examples:

Here is a simple example that I wrote myself. It declares the same enum type and corresponding variables in three different ways.

#include <stdio.h>

enum bool {false, true};
enum bool2 {F, T} true2, false2;
enum bool3 {False, True} false3, true3 = True;

int main(){

  enum bool trueVal = true;
  enum bool falseVal = false;
  printf("True value = %d\n", trueVal);
  printf("False value = %d\n", falseVal);

  printf("\n------------\n");
  
  true2 = T;
  false2 = F;
  printf("True value = %d\n", true2);
  printf("False value = %d\n", false2);
  
  printf("\n------------\n");
  printf("True value = %d\n", true3);
  printf("False value = %d\n", false3);
  return 0;
}

# Output

True value = 1
False value = 0

------------
True value = 1
False value = 0

Here is an example that covers multiple use cases. The identifier is called DAY and the enumeration-list contains both assigned and auto-incremented enumeration-constants.

enum DAY          /* Defines an enumeration type    */
{
  saturday,       /* Names day and declares a       */
  sunday = 0,     /* variable named workday with    */
  monday,         /* that type                      */
  tuesday,
  wednesday,      /* wednesday is associated with 3 */
  thursday,
  friday
} workday;

In this example DAY is given as the enumeration type identifier and the enumeration-list is provided. The workday variable is included as the declartion of the enumeration type and the variable takes places on the same line. After the enumeration type is given the workday variable is then declared as an enum type with a value from the DAY enumeration type.

In this example, a value from the set DAY is assigned to the variable today.

enum DAY today = wednesday;

The name of the enumeration constant is used to assign the value. Since the DAY enumeration type was previously declared, only the enumeration tag (identifier) DAY is necessary.


Conclusion

That’s all for today. This is my sixth round of the “#100daysofcode” challenge. I will be continuing my work from round five into round six. I am currently working through the book “Cracking the Coding Interview” by Gayle Laakmann McDowell. My goal is to become more familiar with algorithms and data structures. This goal was derived from my goal to better understand operating systems and key programs that I use in the terminal regularly e.g. Git. This goal was in term derived from my desire to better understand the fundamental tools used for coding outside of popular GUIs. This in turn was derived from my desire to be a better back-end developer.

I have no idea if my path is correct but I am walking down this road anyways. Worst case scenario I learn a whole bunch of stuff that will help me out on my own personal projects.