A char pointer into a string works exactly like an int pointer into an array — except each step is one byte, one character. This question from our C Programming Quiz App asks what *(s + 2) reads out of "abc". Getting it right means keeping two things straight: where a string pointer starts, and that offsets count from zero.
The Quiz Question
char *s = "abc";
printf("%c", *(s + 2));
What is printed by this code?
- a
- b
- c
- abc
The Correct Answer: c
The string literal "abc" is stored in memory as four bytes: 'a', 'b', 'c', '\0'. The pointer s holds the address of the first byte. s + 2 advances two characters, landing on 'c', and the dereference reads it. Verified with gcc 13.3 and Apple clang 21, both with -Wall -Wextra clean:
$ gcc -Wall -Wextra str.c && ./a.out c
s ──→ [ 'a' ][ 'b' ][ 'c' ][ '\0' ]
s+0 s+1 s+2 s+3
↑ *(s + 2) reads here
Why Each Wrong Answer Is Wrong
Why not “a”?
'a' is *s — offset zero, no arithmetic. We ran printf("%c %c", *s, *(s + 1)) alongside the quiz line and got a b, confirming the layout above. Choosing “a” means reading the pointer’s starting position and ignoring the + 2.
Why not “b”?
This is the classic off-by-one: counting “first, second” instead of “offset 0, offset 1”. 'b' sits at *(s + 1). Offset 2 is the third character.
Why not “abc”?
Printing the whole string requires the %s conversion with the pointer itself: printf("%s", s). Our code uses %c with a single dereferenced character. Mixing these up the other way — passing *s to %s — is a crash waiting to happen, and both compilers warn about it under -Wall.
char *s vs char s[] — One Difference That Bites
Reading through s is fine, but writing is where char *s = "abc" differs from char s[] = "abc":
char *s = "abc"; /* s points at a string literal: read-only */
s[0] = 'x'; /* undefined behavior — typically a segfault */
char t[] = "abc"; /* t is YOUR array, initialized by copy */
t[0] = 'x'; /* fine: t is now "xbc" */
String literals live in read-only storage on modern platforms; the pointer form merely borrows them. The array form copies the characters into writable memory you own. Our quiz code only reads, so both forms would print c — but the distinction matters the moment you modify.
Because *(s + 2) is identical to s[2] (see why pointer arithmetic scales), everything you know about array indexing carries over — this is exactly how functions like strlen walk to the terminating '\0'.
Frequently Asked Questions
Is *(s + 2) the same as s[2]?
Yes — the standard defines s[2] as *(s + 2). For a char pointer each step is exactly one byte, so s + 2 is the third character of the string.
What is the difference between char *s = “abc” and char s[] = “abc”?
The pointer form points at a read-only string literal; writing through it is undefined behavior. The array form copies the literal into a writable array you own. Reading works identically in both.
Why does %c need the dereference but %s doesn’t?
%c expects a character value, so you pass *(s + 2). %s expects a pointer to a NUL-terminated string and walks it itself, so you pass s. Passing the wrong one is a format mismatch both gcc and clang flag with -Wformat.
Related Reading
- Pointers in C – Complete Guide
- Reverse a String Using Pointers
- C Program to Sort a String Alphabetically
- C Aptitude Questions and Answers
Recommended Books
- The C Programming Language – Kernighan & Ritchie (India) | Amazon.com
- C Programming: A Modern Approach – K.N. King (India) | Amazon.com
This question is #17 in the C Programming Quiz App — 155 questions with explanations covering operators, pointers, memory, and more.
Download on Google Play →