A bounded copy leaves room for the null terminator in the destination buffer.

capacity The destination capacity controls how many characters can be copied safely.
leave room Copy at most `capacity - 1` characters, then write the terminator.

Bounded Copy

capacity
bounded_copy.c
Replay: real traced execution (multi-file project)
#include <stdio.h>

int main(void) {
    char source[] = "trace";
    char target[8];
    int capacity = 4;
    int i = 0;

    while (i < capacity - 1 && source[i] != '\0') {
        target[i] = source[i];
        i++;
    }
    target[i] = '\0';

    printf("copy=%s\n", target);
    return 0;
}
#include <stdio.h>

int main(void) {
    char source[] = "trace";
    char target[8];
    int capacity = 3;
    int i = 0;

    while (i < capacity - 1 && source[i] != '\0') {
        target[i] = source[i];
        i++;
    }
    target[i] = '\0';

    printf("copy=%s\n", target);
    return 0;
}
#include <stdio.h>

int main(void) {
    char source[] = "trace";
    char target[8];
    int capacity = 6;
    int i = 0;

    while (i < capacity - 1 && source[i] != '\0') {
        target[i] = source[i];
        i++;
    }
    target[i] = '\0';

    printf("copy=%s\n", target);
    return 0;
}
  1. source ← trace, target ← �7�Z, capacity ← 4, i ← 0

    3int main(void) {4    char source→ trace[] = "trace";5    char target→ �7�Z[8];6    int capacity→ 4 = 4; //@capacity=3, 67    int i→ 0 = 0;
  2. target[i] ← t, i ← 1

    pass 1 of 3
    9while (i0 < capacity4 - 1 && source[i]t != '\0') {10    target[i]→ t = source[i]t;11    i→ 1++;12}
    All 3 passes — pass 1 is the card above
    passsource[i]target[i]i
    1t t0 1
    2r7 r1 2
    3a a2 3
  3. target[i] ←

    12    }13    target[i] = '\0';1415    printf("copy=%s\n", targettra);16    return 0;17}
    outputcopy=tra
  1. source ← trace, target:4:޼k@@END @@TRACE|bounded_copy.c|128617820636096|BEFORE|6.5-6.22:int capacity = 3;|@@END @@TRACE|bounded_copy.c|128617820636096|AFTER|6.5-6.22:int capacity = 3;|6.9-6.17:capacity ← 3

    3int main(void) {4    char source→ trace[] = "trace";5    char target→ 3[8];6    int capacity = 3;7    int i→ 0 = 0;
  2. target[i] ← t, i ← 1

    pass 1 of 2
    9while (i0 < capacity3 - 1 && source[i]t != '\0') {10    target[i]→ t = source[i]t;11    i→ 1++;12}
  3. target[i] ← r, i ← 2

    pass 2 of 2
    9while (i1 < capacity3 - 1 && source[i]r != '\0') {10    target[i]→ r = source[i]r;11    i→ 2++;12}
  4. target[i] ←

    12    }13    target[i] = '\0';1415    printf("copy=%s\n", targettr);16    return 0;17}
    outputcopy=tr
  1. source ← trace, target ← �`�~q, capacity ← 6, i ← 0

    3int main(void) {4    char source→ trace[] = "trace";5    char target→ �`�~q[8];6    int capacity→ 6 = 6;7    int i→ 0 = 0;
  2. target[i] ← t, i ← 1

    pass 1 of 5
    9while (i0 < capacity6 - 1 && source[i]t != '\0') {10    target[i]→ t = source[i]t;11    i→ 1++;12}
    All 5 passes — pass 1 is the card above
    passsource[i]target[i]i
    1t t0 1
    2r` r1 2
    3a a2 3
    4c c3 4
    5e~ e4 5
  3. target[i] ←

    12    }13    target[i] = '\0';1415    printf("copy=%s\n", targettrace);16    return 0;17}
    outputcopy=trace

Exercise: bounded_copy.c

Write a copy helper that truncates safely, always terminates the destination, and reports whether truncation happened