CodeRigor

FREE LESSON

Byte buffers & memory functions

Validate byte ranges before calling memmove; distinguish overlap, byte counts and object representation from typed value operations.

A C API often receives a pointer and a byte count. Neither tells it how much storage is actually available. Your adapter must establish that fact before the call. In C++ the familiar header exposes these C memory functions in std; using them does not change their byte-oriented contracts.

A right shift must preserve the source snapshot
The four original source bytes become positions two through five; the first two bytes remain.
A right shift must preserve the source snapshot
The four original source bytes become positions two through five; the first two bytes remain.

Choose the operation by its preconditions

memcpy copies a known nonoverlapping range. memmove supports overlap. Neither scans for a terminator or checks capacity. In a right shift, writing the first destination byte can overwrite the next source byte; a handwritten forward loop is therefore not a general replacement for memmove. Left shifts that happen to work do not prove that loop correct.

A memory-function count is in bytes. For an array of records, count times sizeof(record) must fit size_t before allocating or transferring. Inside one existing span, validate the starting positions first and compare the requested count with size minus each position. Computing the endpoint by addition can wrap and incorrectly approve an enormous request.

Follow one complete example

Run this program, then change one boundary while keeping the API preconditions valid. Predict its output before pressing Run.

C++
#include <array>
#include <cstddef>
#include <cstdio>
#include <cstring>
int main() {
    std::array<unsigned char,6> bytes{10,20,30,40,50,60};
    std::memmove(bytes.data()+2,bytes.data(),4);
    for(auto b:bytes) std::printf("%u ",unsigned(b));
    std::puts("");
}
Validate before moving
Positions must fit before subtraction can describe remaining capacity.
Validate before moving
Positions must fit before subtraction can describe remaining capacity.

Bytes are not automatically values

memcmp compares object representations and only promises the sign of its result. Padding bytes, multiple representations and field interpretation make it unsuitable as a general struct equality operator. A zero fill is a byte operation too: do not use memset as a constructor for std::string, a virtual object or a resource-owning class.

For a trivially copyable type there are specific representation-copy guarantees. They do not permit bypassing every lifetime, alignment or aliasing rule. This exercise stays entirely within already-existing std::byte elements so the operation has a clear, bounded meaning. Use typed algorithms, assignment or bit_cast where their stronger types express the actual operation.

Memory operation choices
Choose by overlap and meaning, rather than by a faster-looking name.
Memory operation choices
Choose by overlap and meaning, rather than by a faster-looking name.

Make the empty case explicit

An empty span may have a null data pointer. A wrapper can return success for its valid zero-length case without passing that pointer to a C function or computing pointer arithmetic on it. Positions beyond the end are still invalid even if the count is zero.

State the failure guarantee before implementing the copy: a rejected range changes nothing. Test invalid requests against a saved snapshot as well as checking the returned bool. For overlap, derive the expected result from a separate source snapshot so the test does not repeat the same copy algorithm.

Read the return value

Predict this smaller case. The check item later changes the values, so explain the rule as well as the output.

C++
#include <cstdio>
#include <cstring>
int main() { char b[]="ABCDE"; std::memmove(b+1,b,4); std::puts(b); }

Complete the faded example

State the missing precondition or result check before filling the code. The fill exercise supplies the rest of the implementation.

C++
if (source > storage.size() || destination > storage.size()) return false;
// Fill: validate count without forming an overflowing endpoint.
// Fill: implement a valid zero-length no-op and an overlapping move.

Check your model

A move with source == destination and a valid nonzero count should succeed. Which validation rule makes that work without a special copy loop?

Practice the boundary

Implement bool move_bytes(std::span<std::byte> storage, std::size_t destination, std::size_t source, std::size_t count).

Move exactly count bytes within one borrowed buffer, as if copied through temporary storage. Both overlapping directions and identical ranges must work. Use the C memory-function interface.

Accept positions at the end only when the requested count is zero. Reject any position beyond the end or any range that does not fit; return false without changing any bytes. Avoid overflow in range arithmetic. A valid zero-length operation, including an empty span, succeeds without dereferencing pointers. Return true on success. No allocation or ownership transfer is needed.

Read → six checks → two bug hunts → fill → build. A successful graded submission is evidence; reading or watching alone does not grant mastery. Review cards reinforce API choices separately.

Watch and verify

The Watch & read panel links a free lecture for the relevant background and primary API references. The lecture notes say which parts are background; the tested contract here supplies the exact wrapper policy.

C standard-library course · C library review cards · Unix/Linux systems

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →