Pages

Tuesday, September 30, 2014

Programming in C: Few Tidbits #3

1) Not able to redirect the stdout output from a C program/application to a file

Possible cause:

Buffered nature of standard output (stdout) stream. Might be waiting for a newline character, for the buffer to be full, or for some other condition to be met based on implementation.

Few potential workarounds:

  • Explicit flushing of standard output stream where needed.
        fflush(stdout);

            -or-

  • Relying on no buffering standard error (stderr) in place of stdout stream.

            -or-

  • Turning-off buffering explicitly by calling setbuf() or setvbuf().
    eg.,
    
    /* just need one of the following two calls, but not both */
    setbuf (stdout, NULL);
    setvbuf(stdout, NULL, _IONBF, 0);  // last argument value need not really be zero
    

2) Printing ("escaping" maybe?) a percent sign (%) in a printf formatted string

Conversion/format specifiers start with a % sign, and using the slash sequence to escape the % sign in strings that are not format specifiers usually does not work. Check the following example out.

eg.,

Executing the following code:

        int pct = 35;
        printf("\n%d%", pct);

.. results in:

35, but not 35% as one would expect.

Format specifier "%%" simply prints the percent sign - so, the desired result can be achieved by replacing "%d%" with "%d%%" in printf statement.

        int pct = 35;
        printf("\n%d%%", pct);

.. shows:

35% as expected

(web search keywords: C printf conversion specification)


3) Duplicating a structure

If the structure has no pointers, assigning one struct to another struct duplicates the structure. The same effect can be achieved by using memcpy() too, but it is not really necessary. After the execution of struct assignment, there will be two copies of struct with no dependency - so, they can be operated independently without impacting the other. The following sample code illustrates this point.

eg., #1
 ...
 ...

 typedef struct human {
  int accno;
         int age;
 } person;

 ...
 ...

 person guy1, guy2;

 guy1.accno = 20202;
 guy1.age = 10;

 guy2 = guy1;

 printf("\nAddress of:\n\t-> guy1: %p. guy2: %p", guy1, guy2);

 printf("\n\nBefore update:\n");
 printf("\naccno of:\n\t-> guy1: %d. guy2: %d", guy1.accno, guy2.accno);
 printf("\nage of:\n\t-> guy1: %d. guy2: %d", guy1.age, guy2.age);

 guy1.age = 15;
 guy2.accno = 30303;

 printf("\n\nAfter update:\n");
 printf("\naccno of:\n\t-> guy1: %d. guy2: %d", guy1.accno, guy2.accno);
 printf("\nage of:\n\t-> guy1: %d. guy2: %d", guy1.age, guy2.age);

 ...
 ...
 

Execution outcome:

Address of:
        -> guy1: ffbffc38. guy2: ffbffc30

Before update:

accno of:
        -> guy1: 20202. guy2: 20202
age of:
        -> guy1: 10. guy2: 10

After update:

accno of:
        -> guy1: 20202. guy2: 30303
age of:
        -> guy1: 15. guy2: 10

On the other hand, if the structure has pointer variable(s), duplication of a structure using assignment operator leads to pointer variables in both original and copied structures pointing to the same block of memory - thus creating a dependency that could potentially impact both pointer variables with unintended consequences. The following sample code illustrates this.

eg., #2
 ...
 ...

 typedef struct human {
         int *accno;
         int age;
 } person;

 ...
 ...

 person guy1, guy2;

 guy1.accno = malloc(sizeof(int));
 *(guy1.accno) = 20202;

 guy1.age = 10;
 guy2 = guy1;
 
 ...
 ...

 guy1.age = 15;
 *(guy2.accno) = 30303;

 ...
 ...
Execution outcome:
Address of:
        -> guy1: ffbffb48. guy2: ffbffb40

Before update:

accno of:
        -> guy1: 20202. guy2: 20202
age of:
        -> guy1: 10. guy2: 10

After update:

accno of:
        -> guy1: 30303. guy2: 30303
age of:
        -> guy1: 15. guy2: 10

Few people seem to refer this kind of duplication as shallow copy though not everyone agrees with the terminology.

If the idea is to clone an existing struct variable that has one or more pointer variables, then to work independently on the clone without impacting the struct variable it was cloned from, one has to allocate memory manually for pointer variables and copy data from source structure to the destination. The following sample code illustrates this.

eg., #3
 ...
 ...

 typedef struct human {
         int *accno;
         int age;
 } person;

 ...
 ...

 person guy1, guy2;

 guy1.accno = malloc(sizeof(int));
 *(guy1.accno) = 20202;

 guy1.age = 10;

 guy2.age = guy1.age;
 guy2.accno = malloc(sizeof(int));
 *(guy2.accno) = *(guy1.accno);

 ...
 ...

 guy1.age = 15;
 *(guy2.accno) = 30303;

 ...
 ...

Execution outcome:

Address of:
        -> guy1: ffbffaa8. guy2: ffbffaa0

Before update:

accno of:
        -> guy1: 20202. guy2: 20202
age of:
        -> guy1: 10. guy2: 10

After update:

accno of:
        -> guy1: 20202. guy2: 30303
age of:
        -> guy1: 15. guy2: 10

This style of explicit duplication is referred as deep copy by few people though not everyone agrees with the terminology.

No comments:

Post a Comment