Difficulty: ★ ★ ★ ☆
Pointers can drive C programmers mad. In fact, I’d say that evidence of this notion is that the most experienced C programmers have an air of insanity about them. To join their club, try working this month’s Exercise.
To start, consider the following program:
2025_02_01-Exercise.c
#include <stdio.h> int main() { char *a[] = { "I", "good", "language" }; char *b[] = { "am", "C", "excellent", "an" }; char *c[] = { "a", "programmer", "very" }; printf("%s %s %s %s %s %s %s\n", a[0], b[0], c[0], c[2], a[1], b[1], c[1] ); return 0; }
Three arrays contain various strings. These strings are used in a printf() statement, generating this output:
I am a very good C programmer
This output is rather easy to guess if you’ve been programming C a while. Just ignore the pointers and use array notation to output the string. But more words are available in the arrays than are output, which hints at this month’s challenge.
Your goal is to output this string:
I am an excellent C programmer
Before you start coding, you must add another pointer variable, **z
, declared as follows:
char **z[] = { a, b, c };
Using pointer variable z
— and only pointer variable z
— you are to modify the printf() statement so that it outputs the string, "I am an excellent C programmer"
.
Once you figure out how to get the first word out, the rest aren’t as big of an issue. But hopefully this challenge gets your brain to think about pointers and asterisks and parentheses and all of that.
Click here to view my solution.
Havenʼt posted in a while, but I read your blog regularly and this piqued my interest. Quite a clever little exercise. Especially considering the original phrase consists of 7 words while the requested output only has 6… if one doesnʼt want to modify the given printf format string, the best one can manage is probably “I am an excellent C programmer ” (with a superfluous space at the end).
The only gripe I have with the above is that itʼs not ANSI C, because ‘a’, ‘b’ and ‘c’ arenʼt “constant expressions”. (On the other hand itʼs true that—as per ISO/IEC 9899:1999, §6.7.8p4—runtime array initializers have legal since C99, so I guess my remark only shows that Iʼm getting old.)
Anyway, for some added difficulty it might be fun to try the above exercise without relying on Cʼs array subscript operator ☺
Welcome back!
To your future cheerfulness, I can state that my solution does not use array notation.
«I can state that my solution does not use array notation.»
I already thought as much… just wanted to mention it, because the exercise leaves it open.
This probably isn’t what you wanted but at least it works. The ycoords and xcoords stuff could be streamlined a bit but it’ll do for now.
#include <stdio.h>
int main()
{
char *a[] = { “I”, “good”, “language” };
char *b[] = { “am”, “C”, “excellent”, “an” };
char *c[] = { “a”, “programmer”, “very” };
char **z[] = { a, b, c };
// arrays of row and column numbers denoting words to print
// will probably blow up if any indexes exceed a, b, c or z sizes
int ycoords[] = {0,1,1,1,1,2};
int xcoords[] = {0,0,3,2,1,1};
// iterate number of words
for(int i = 0; i <= 5; i++)
{
// use current y and x coordinates to get at required word
printf(“%s”, *(*(z+ycoords[i])+xcoords[i]));
// if not at end print space
if(i < 5)
printf(“%s”, ” “);
}
puts(“.”);
return 0;
}
>>This probably isn’t what you wanted but at least it works.<<
What I really like about challenges like these is getting to see how different people approach a problem. Mine wasn't nearly as adventurous:
// Code challenge:
// Output the string, "I am an excellent C programmer"
// From Dan Gookin's "C For Dummies" blog
// https://c-for-dummies.com/blog/?p=6791
// https://totally-out-of-ideas.blogspot.com/2025/02/fun-c-code-challenge.html
#include
int main(void)
{
char *a[] = { “I”, “good”, “language” };
char *b[] = { “am”, “C”, “excellent”, “an” };
char *c[] = { “a”, “programmer”, “very” };
char **z[] = { a, b, c };
// Easier way:
printf(“%s %s %s %s %s %s.\n”,
z[0][0],
z[1][0],
z[1][3],
z[1][2],
z[1][1],
z[2][1]
);
// A bit trickier for this rusty old mind. 🙂
printf(“%s %s %s %s %s %s.\n”,
*(*(z + 0) + 0),
*(*(z + 1) + 0),
*(*(z + 1) + 3),
*(*(z + 1) + 2),
*(*(z + 1) + 1),
*(*(z + 2) + 1)
);
return 0;
}
I admire the clever solutions! Mine shall be boring by comparison. ☹️
I’ll go with the author Richard M. Reese of “Understanding and Using C Pointers: Core Techniques for Memory Management”. He writes:
“Compact expressions can be very descriptive but can also be cryptic, as pointer notation is not always fully understood by many programmers. Compact expressions should address a specific need and not be cryptic just to be cryptic. For example, in the following sequence, the third character of the names’ second element is displayed with two different printf functions … While the two approaches are equivalent
and will display the character ‘n’, the simpler approach is to use array notation:
“`c
char *names[] = {“Miller”, “Jones” , “Anderson” };
printf(“%c\n”. ,*(*(names+1)+2));
printf(“%c\n” , names [1][2]); ”
“`
My solution uses array notation 🙂
“`c
#include
#include
int main(void)
{
char *a[] = { “I”, “good”, “language” };
char *b[] = { “am”, “C”, “excellent”, “an” };
char *c[] = { “a”, “programmer”, “very” };
char **z[] = { a, b, c };
printf(“%s %s %s %s %s %s\n”,
z[0][0], // “I”
z[1][0], // “am”
z[1][3], // “an”
z[1][2], // “excellent”
z[1][1], // “C”
z[2][1] // “programmer”
);
return EXIT_SUCCESS;
}
“`
I completely concur with Mr. Reese: In my code, I always opt for simple over the cool or obfuscated. These are all valid solutions.
Thank you!
@chikega Well stated.
I am of the same mind as both of you on this. The easier to understand, the better.