G27
Self-checkedTier 1 13 min readpds.pointers-arrays-strings

Arrays, strings and pointers together

Arrays and pointers look interchangeable in C but are different things. Learn exactly where they differ (sizeof, assignment, &a), how a string is just a char array ending in a zero byte, why modifying a literal is undefined, and the idioms such as while (*d++ = *s++) that exam questions are built from.

Why it exists

In C the name of an array is silently turned into a pointer in most expressions, and text is stored as an array of characters with no length field. These two facts make C compact, and they make a large share of C exam questions tricky: the same code can be read as "array" or as "pointer", and sizeof, assignment and & treat the two differently.

Prerequisites

Precise definitions

Arrays versus pointers

An array name decays to a pointer to its first element in nearly every expression (see the arrays page). The exceptions are the operand of sizeof, the operand of unary &, and a string literal used to initialise an array. That does not make an array a pointer. The two are different objects:

int a[5];int *p;
What it isfive ints, in a blockone variable that holds an address
sizeof5×4=205 \times 4 = 208 (on a 64-bit machine)
a = ... / p = ...error: an array is not assignableallowed
a++ / p++errorallowed
&aaddress of the whole array, type int (*)[5]&p is int **, the address of the pointer
Where the data isin the array itselfwherever p points

a[i] and p[i] are both computed as *(a + i) and *(p + i), so the syntax of indexing is the same. The difference is that for a the array's cells start at a, whereas for p the program must first load the pointer, then add.

a versus &a. Both have the same numerical address, but different types. a + 1 moves one element (4 bytes). &a + 1 moves one whole array (20 bytes). This is a classic trick question.

Strings

  • A string in C is a sequence of char values ending with a null character '\0' (the byte whose value is 0). There is no length stored anywhere. Functions find the end by looking for the null character.
  • The length of a string is the number of characters before the null character. strlen("GATE") is 4. The size of the array that holds it is at least 5. sizeof("GATE") is 5.
  • A string literal such as "GATE" is an array of char with static storage duration. Modifying a string literal is undefined behaviour. On the usual platform it is placed in read-only memory (see the memory layout page), so the attempt crashes.
  • 'a' is a character constant. In C its type is int (in C++ it is char), so sizeof 'a' is 4 wherever int is 4 bytes, as on gcc/x86-64. "a" is a string literal: two bytes, 'a' and '\0'.

Three ways to hold a string

DeclarationWhat existsWritable?sizeof
char s[] = "GATE";a 5-byte array on the stack (or data area) that was initialised from the literalyes5
char s[10] = "GATE";a 10-byte array: G A T E then six '\0'yes10
const char *t = "GATE";one pointer; it points at the literal in read-only memoryno8

The animation below shows the first and the third together. The array holds its own private copy of the text. The pointer holds only an address, and the text it points at is somewhere else.

A char array and a pointer to a literal

Real run, real addresses

C source

1#include <stdio.h>
2
3int main(void) {
4 char s[] = "GATE";
5 const char *t = "GATE";
6 char *u = s;
7 u = u + 2;
8 *u = 'X';
9 int n = 0;
10 while (t[n] != '\0') {
11 n++;
12 }
13 return 0;
14}

Stack

schar

'G'…d60b
[0]
'A'…d60c
[1]
'T'…d60d
[2]
'E'…d60e
[3]
'\0'…d60f
[4]

Read-only data (string literals)

nothing here yet

Amber = changed in this step. Hover a cell for its full address. Arrows show where a pointer points; the small tag under a cell names the pointers aimed at it.

Step 1

s is an array of 5 chars: G, A, T, E and the terminating null character. The compiler copied the text into the array, so it is private and writable.

1 / 10
char s[] makes a private writable copy on the stack. const char *t points at the string literal in read-only memory. Produced by: real execution: every address and value is read from memory by the running program at each step. gcc (Debian 14.2.0-19) 14.2.0. gcc -O0 -o prog prog.c && setarch x86_64 -R ./prog (ASLR off so the numbers are stable)

The standard string functions (<string.h>)

FunctionWhat it doesDanger
strlen(s)number of characters before '\0'needs a terminated string
strcpy(d, s)copies s including the '\0' into dd must have room for strlen(s) + 1 bytes and the two must not overlap, otherwise undefined
strcat(d, s)appends s to the end of dd must already be a terminated string with room for both strings and the '\0'; no overlap
strcmp(a, b)compares character by character (as unsigned char) until a difference or the end; returns negative, zero or positivethe result is not guaranteed to be −1-1 or 11
printf("%s", s)prints characters until '\0'an unterminated array makes it read past the end

== between two strings compares the addresses, not the contents. Use strcmp(a, b) == 0 to test equality.

Arrays of pointers versus two-dimensional arrays

const char *p[] = {"ab", "cde", "f"}; is an array of three pointers, each aiming at a literal of its own length. char q[3][4] = {"ab", "cde", "f"}; is a rectangle of 3×4=123 \times 4 = 12 chars, each row padded with zeros. The first costs 3×83 \times 8 bytes for the pointers (plus the literals), the second costs 12.

How it works

Most programs that walk a string use a pointer that advances until it meets the null character. Two idioms appear again and again, and both are exam favourites.

Length by pointer.

int len(const char *s) {
    const char *p = s;
    while (*p) p++;
    return (int)(p - s);
}

*p is false only at the null character (value 0), so the loop stops there. p - s is the number of elements walked, which is the length.

Copy by pointer.

while ((*d++ = *s++))
    ;

Read it as: copy *s into *d, then advance both pointers. The value of the whole assignment expression is the character just copied. The loop therefore ends after the null character has been copied, so the destination is correctly terminated.

Worked examples

EX 1sizeof versus strlen

Easy
#include <stdio.h>
#include <string.h>
 
int main(void) {
    char s[] = "GATE";
    char t[10] = "GATE";
    const char *u = "GATE";
    printf("%zu %zu %zu %zu\n", sizeof s, sizeof t, sizeof u, strlen(t));
    return 0;
}

Output (64-bit):

5 10 8 4

Reading it. s has exactly 5 cells (four letters and the null character). t was declared with 10 cells, so sizeof t is 10, but its string is still 4 characters long. u is a pointer, so sizeof u is 8. strlen is the only one of the four that looks at the content.

EX 2a, &a and the size of one step

Easy
#include <stdio.h>
 
int main(void) {
    int a[5] = {10, 20, 30, 40, 50};
    printf("%td %td\n", (char *)(a + 1) - (char *)a, (char *)(&a + 1) - (char *)a);
    return 0;
}

Output:

4 20

Reading it. a + 1 steps over one int, 4 bytes. &a has type "pointer to array of 5 ints", so &a + 1 steps over the whole array, 20 bytes, and lands exactly one past its end. (Casting to char * makes the subtraction count bytes.)

EX 3Printing from the middle of a string

Medium
#include <stdio.h>
 
int main(void) {
    char s[] = "ABCDEF";
    printf("%s %c %s %c\n", s + 3, *(s + 1), &s[4], "GATE"[2]);
    return 0;
}

Output:

DEF B EF T

Reading it. s + 3 points at 'D', and %s prints from there to the null character: DEF. *(s + 1) is 'B'. &s[4] is the address of 'E', so %s prints EF. A string literal is an array, so it can be indexed directly: "GATE"[2] is 'T'.

EX 4Converting a string in place with a pointer

Medium
#include <stdio.h>
 
int main(void) {
    char s[] = "gate";
    for (char *p = s; *p; p++) *p = *p - 'a' + 'A';
    printf("%s\n", s);
    return 0;
}

Output (ASCII):

GATE

Reading it. The loop condition *p is the character itself, so it stops at the null character. *p - 'a' is the letter's position in the alphabet (0 to 25), and adding 'A' gives the capital letter. This works because s is a writable array. Replacing char s[] = "gate" with char *s = "gate" would try to write into the literal, which is undefined.

EX 5Trace the copy idiom

GATE level
#include <stdio.h>
 
int main(void) {
    char src[] = "AB";
    char dst[3] = {'x', 'y', 'z'};
    char *s = src, *d = dst;
    int steps = 0;
    while ((*d++ = *s++)) steps++;
    printf("%d %zu %c%c%d\n", steps, (size_t)(d - dst), dst[0], dst[1], dst[2]);
    return 0;
}

Output:

2 3 AB0

Trace. Before the loop s is at 'A' and d at dst[0].

IterationCopiedValue of the assignmentsteps after
1'A' into dst[0]'A' (true)1
2'B' into dst[1]'B' (true)2
3'\0' into dst[2]0 (false), the loop stops2

The null character is copied, so dst[2] becomes 0 (printed as the number with %d). d ended up one past the null character: 3 elements from dst, so d - dst is 3. steps counts the characters, not the terminator.

EX 6== on strings compares addresses

GATE level
#include <stdio.h>
#include <string.h>
 
int main(void) {
    char a[] = "GATE";
    char b[] = "GATE";
    const char *p = a, *q = b;
    printf("%d %d\n", p == q, strcmp(a, b) == 0);
    return 0;
}

Output:

0 1

Reading it. a and b are two different arrays, so their addresses differ and p == q is false, although the letters are identical. strcmp compares the letters and finds them equal, so strcmp(a, b) == 0 is true. (Whether two identical literals share one address is the compiler's choice, so questions about that are not answerable.)

EX 7Array of pointers versus 2-D array of chars

GATE level
#include <stdio.h>
#include <string.h>
 
int main(void) {
    const char *p[] = {"ab", "cde", "f"};
    char q[3][4] = {"ab", "cde", "f"};
    printf("%zu %zu %zu %zu\n", sizeof p, sizeof q, strlen(p[1]), strlen(q[1]));
    return 0;
}

Output (64-bit):

24 12 3 3

Reading it. p is three pointers: 3×8=243 \times 8 = 24 bytes, and the literals live elsewhere. q is 3×4=123 \times 4 = 12 bytes of characters, with short rows padded by zeros. The string lengths agree (3), because strlen stops at the first null character in either layout.

Cheat box

Cheat box

  • Array ≠\neq pointer: sizeof, assignability, and & differ. Indexing syntax is shared.
  • a + 1 moves one element. &a + 1 moves the whole array.
  • String = char array ending with '\0'. strlen excludes it, sizeof of the array includes it.
  • char s[] = "x" is a writable copy. char *t = "x" points at a literal. Modifying a literal is undefined (it is normally in read-only memory).
  • sizeof 'a' is 4 in C (type int, 4 bytes here). sizeof "a" is 2.
  • strcpy needs strlen(src) + 1 bytes. strcmp returns negative, zero or positive.
  • == on strings compares addresses. Use strcmp.
  • while ((*d++ = *s++)); copies including the terminator.
  • const char *p[3] is 3 pointers. char q[3][4] is 12 chars.

Traps and GATE patterns

Connections

The arrays page covers indexing and addresses, and pointers the arithmetic used here. Where a string literal usually lives (read-only memory, which is why modifying one normally crashes) is a fact about the memory layout. Passing an array to a function really passes a pointer, shown on the functions page. Strings in the theory of computation are a different object: mathematical sequences with no terminator (alphabets, strings and languages).

PYQs

9 previous year questions from your book. I re-solved each one myself (9 by running or simulating, 0 by reasoning only); the book's key is shown next to my answer. All PYQs

GATE 2015 · Set 2 · MCQ · 1 markQ27 · page 23 of the book
Consider the following function written the C
programming language.
 void foo (char *a) {
    if (*a && *a != '   ') {
        foo (a+1);
        putchar (*a);
    }
}
The output of the above function on input
"ABCD EFGH" is
  • (a)ABCD EFGD
  • (b)ABCD
  • (c)HGFE DCBA
  • (d)DCBA
GATE 2025 · Set 2 · MCQ · 1 markQ3 · page 39 of the book
Consider the following C program:

#include < stdio.h >
int main(){
int a;
int arr[5] = {30,50,10};
int *ptr;
ptr = &arr[0] + 1;
a = *ptr;
(*ptr)++;
ptr++;
printf("%d", a + (*ptr) + arr[1]);
return 0;
}

The output of the above program is__________  .
(Answer in integer)
GATE 2025 · Set 2 · MCQ · 1 markQ4 · page 39 of the book
Consider the following C program:

#include < stdio.h >
void stringcopy(char *, char *);
int main(){
    char a[30] = "@#Hello World!";
    stringcopy(a, a + 2);
    printf("%s\n", a);
    return 0;
}
void stringcopy(char *s, char *t) {
    while(*t)
        *s++ = *t++;
}

Which ONE of the following will be the output of the
program?
  • (a)@#Hello World!
  • (b)Hello World!
  • (c)ello World!
  • (d)Hello World!d!
GATE 2019 · NAT · 2 marksQ9 · page 40 of the book
Consider the following C program:
#include <stdio.h>
int main() {
    int a[] = {2, 4, 6, 8, 10};
    int i, sum = 0, *b = a + 4;
    for (i = 0; i < 5; i++)
        sum = sum + (*b - i) - *(b - i);
    printf("%d\n", sum);
    return 0;
}
The output of the above C program is ____ .
GATE 2019 · NAT · 1 markQ10 · page 41 of the book
Consider the following C program:
#include <stdio.h>
int main (){
   int arr []={1,2,3,4,5,6,7,8,9,0,1,2,5},
   *ip = arr+4;
    printf ("%d\n", ip[1]);
    return 0;
}

The number that will be displayed on execution of the
program is _____.
GATE 2017 · Set 2 · NATQ17 · page 42 of the book
Consider the following C program.
#include<stdio.h>
#include<string.h>
int main ()  {
      char* c = "GATECSIT2017";
      char* p = c;
      printf("%d", (int) strlen (c + 2[p] - 6[p] - 1));
      return 0;
}
The output of the program is _________ .
GATE 2015 · Set 3 · MCQ · 1 markQ20 · page 43 of the book
Consider the following C program segment.
# include <stdio.h>
int main( )
{
char s1[7] = "1234", *p;
p = s1 + 2;
*p = '0' ;
printf ("%s", s1);
}
What will be printed by the program?
  • (a)12
  • (b)120400
  • (c)1204
  • (d)1034
GATE 2011 · MCQ · 1 markQ24 · page 44 of the book
What does the following fragment of C-program print?
char c[] = "GATE2011";
char *p =c;
printf("%s", p + p[3] - p[1]) ;
  • (a)GATE2011
  • (b)E2011
  • (c)2011
  • (d)011
GATE 2010 · MCQ · 2 marksQ25 · page 44 of the book
#include<stdio.h>
int f(int *a, int n)
{
    if(n <= 0) return 0;
    else if(*a % 2 == 0)
    return *a+f(a+1, n-1);
  Else   return *a - f(a+1, n-1);
}
int main()
{
  int a[] = {12, 7, 13, 4, 11, 6};
printf("%d", f(a, 6));
getchar();
  return 0;
}
 What is the value printed by the following C
program
  • (a)-9
  • (b)5
  • (c)15
  • (d)19

Self-check

Question 1

char s[10] = "GATE"; What are sizeof s and strlen(s), and what is the value of s[7]?

Show answer

sizeof s is 10 and strlen(s) is 4. Elements not covered by the initialiser are set to zero, so s[7] is '\0'.

Question 2

What does this print?

#include <stdio.h>
 
int main(void) {
    char s[] = "COMPILER";
    char *p = s + 2;
    printf("%s %c %td\n", p, p[3], p - s);
    return 0;
}
Show answer

p points at 'M', so %s prints MPILER. p[3] is the character three places on from 'M', which is 'L'. p - s is 2.

MPILER L 2

Question 3

Is char *s = "abc"; s[1] = 'X'; a compile-time error, a run-time crash, or well defined?

Show answer

The code compiles. The behaviour is undefined: the literal may not be modified. On typical systems the program crashes, but the standard promises nothing.

Question 4

What are sizeof('a') and sizeof("a") in C?

Show answer

'a' is an int constant: 4. "a" is the array {'a', '\0'}: 2.

Question 5

A destination buffer is char buf[8]. What is the longest string that can be safely copied into it with strcpy?

Show answer

strcpy writes the characters and the terminator, so the string length plus one must be at most 8. The longest safe string has 7 characters.

Revision card

One-screen revision

  • Array and pointer differ in sizeof, assignment, and &. a + 1 moves an element, &a + 1 moves the array.
  • String = chars + '\0'. strlen excludes the terminator; sizeof of the array includes it.
  • char s[] = "x": writable copy. char *t = "x": read-only literal. Writing to it is undefined.
  • sizeof 'a' is 4 (int constant on gcc/x86-64), sizeof "a" is 2.
  • strcpy needs length + 1. strcmp is negative, zero or positive. == compares addresses.
  • while ((*d++ = *s++)); copies the terminator too.
  • const char *p[n] is nn pointers; char q[n][m] is n⋅mn \cdot m chars.

References

  • ·Kernighan and Ritchie, The C Programming Language, 2nd ed., Sections 1.9 Character Arrays, 5.3 Pointers and Arrays, 5.5 Character Pointers and Functions, 5.6 Pointer Arrays; Pointers to Pointers, Appendix B3 String Functions
  • ·ISO/IEC 9899:2011 (C11), Sections 6.3.2.1 Lvalues, arrays, and function designators, 6.4.5 String literals, 6.5.3.4 The sizeof operator, 6.7.9 Initialization, 7.24 String handling

Verification

The animation replays a real run of an instrumented C program: every address, character and pointer target is read from memory at each step, and the test suite checks that the array copy was changed while the literal was not and that the literal sits at a lower address than the stack array. All C programs on this page are compiled with -Wall -Wextra -Werror and run by npm run verify:c. Examples assume ASCII letters, a 4-byte int and an 8-byte pointer, as on the usual gcc platforms. The textbook section numbers were written from memory and have NOT been checked against the books. The prose and the GATE-pattern claims have NOT yet had a human textbook check (the independent second pass is described at the end of these notes). SECOND PASS (2026-11-02, done by the assistant, not a human check): every Self-check question was solved before the printed answer was read and all agreed; the definitions, worked examples, cheat box and traps were read claim by claim and the numbers re-derived by hand (long C programs were not re-read line by line: they are compiled and compared by npm run verify:c, and their printed outputs were checked against the prose). No defect found. Status raised to self-checked; verified needs a textbook or human check.

last verified: never