Day 71: Wonky Substitutions in C’s printf()

I was working on understanding a bug in my printing array addresses code from yesterday. The values were off by one each and I wondered if I was missing something about the '\0' character in C. Thankfully it was not about the character and more about the printf function from the C standard library and how it substitutes values. I took some notes and I’m all good now.

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 was trying to play around with addresses in multi-dimensional arrays but I got caught up in trying to understand the bug in my code yesterday. To keep it simple, the printf function is a bit confusing in how it order it’s substitutions. I included an example below. At first I thought it was a stack data structure with the last argument listed being the first to be evaluated but then I got varied results in different prints. So now I don’t know. I just know that you should be careful while trying to inline increment if the value you are incrementing is depended on by other values in the substitution arguments.

C Printing and Incrementing consistently Note

NOTE: When substituting values while performing inline increments things can get wonky. It is safer to separate them unless you are only substituting the value you want to increment once in the function. It seems that when the function evaluates the substitutions the increment will always be processes first and the other dependent values will therefore be affected. It is best to separate the increment from the substitution in this case. Here is an example:

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

int main(){
  int i = 0;
  // incorrect
  while(i < 5)
    printf("Row: %i\tColumn: %i\n", i, i++);

  printf("\n\n");

  // incorrect
  i = 0;
  while(i < 5)
    printf("Row: %i\tColumn: %i\n", i++, i);

  printf("\n\n");

  // correct
  i = 0;
  while(i < 5){
    printf("Row: %i\tColumn: %i\n", i, i);
    ++i;
  }

  return 0;
}
Row: 1  Column: 0
Row: 2  Column: 1
Row: 3  Column: 2
Row: 4  Column: 3
Row: 5  Column: 4


Row: 0  Column: 1
Row: 1  Column: 2
Row: 2  Column: 3
Row: 3  Column: 4
Row: 4  Column: 5


Row: 0  Column: 0
Row: 1  Column: 1
Row: 2  Column: 2
Row: 3  Column: 3
Row: 4  Column: 4

Only in Example 3 do we get the expected result. Tbh, there may be some connection like a stack data structure being utilized in the printf function but I just don’t know and don’t have the time to dive deeper. For now just add an extra line of code to get the consistent results we want.

Solved Print Addresses of Copied Strings programs

/*
 * 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>
#include <string.h>    // Add the header file for string functions

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;
  i = 0;
  while(*copyCharPtr != '\0'){
    printf("Copied String: %c\tAddress: %d\tArray Index: %i\n", *copyCharPtr, copyCharPtr, i++);
    ++copyCharPtr;
  }

  printf("\n\n");
  printf("\nLength of original string: \t%i", strlen(charString));
  printf("\nLength of copy string: \t%i", strlen(charStringCopy));

  printf("\n");
  printf("\n\nSize of original string: \t%i", sizeof(charString));
  printf("\nSize of copy string: \t%i", sizeof(charStringCopy));

  return 0;
}
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: 6422284        Array Index: 0
Copied String: e        Address: 6422285        Array Index: 1
Copied String: l        Address: 6422286        Array Index: 2
Copied String: l        Address: 6422287        Array Index: 3
Copied String: o        Address: 6422288        Array Index: 4
Copied String:          Address: 6422289        Array Index: 5
Copied String: W        Address: 6422290        Array Index: 6
Copied String: o        Address: 6422291        Array Index: 7
Copied String: r        Address: 6422292        Array Index: 8
Copied String: l        Address: 6422293        Array Index: 9
Copied String: d        Address: 6422294        Array Index: 10



Length of original string:      11
Length of copy string:  11


Size of original string:        12
Size of copy string:    12

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.