C Array Copying Guide: memcpy vs for-loop vs strcpy

目次

1. Introduction

The Importance of “Array Copying” in C

When programming in C, you often encounter situations where you want to copy the contents of an array to another array. For example, when you want to back up data or keep values in another variable for temporary processing. However, compared to high-level languages, C provides little support for memory operations, and array copying is not performed automatically, so you need to write the copy logic manually. Moreover, getting the method wrong can lead to serious bugs such as “unexpected behavior” or “memory corruption.” Therefore, understanding the correct copying methods and handling arrays safely and efficiently is a crucial skill when learning C.

Many Struggle with Array Copying

In fact, many people search for the keyword “C array copy,” indicating a high demand.
  • Can you copy instantly using memcpy?
  • What’s the difference from strcpy?
  • Is copying one element at a time with a for loop safer?
  • How do you write a copy using pointers?
To answer these questions, this article clearly explains the basics to advanced techniques of array copying in C.

What You’ll Learn in This Article

By reading this page, you will gain the following knowledge.
  • Fundamental concepts of arrays in C
  • Multiple ways to copy arrays, along with their advantages and cautions
  • Tips and pitfalls when copying strings (char arrays)
  • Q&A-style explanations for common questions
We will provide a thorough explanation with sample code so that even C beginners can understand easily. In the next sections, let’s start by looking at the basics of arrays.

2. Basic Concepts of Arrays

What Is an Array?

In C, an array (Array) is a variable that stores elements of the same data type contiguously. For example, instead of defining five separate int variables to hold the scores of five people, you can handle them together with a single array.
int scores[5];
You can access the elements of such an array by specifying indices starting from 0.
scores[0] = 80;
scores[1] = 75;
scores[2] = 90;
scores[3] = 60;
scores[4] = 85;
Here we assign integers to the five elements scores[0] through scores[4]. Note that indices start at 0.

How to Initialize an Array

You can also initialize an array at the time of declaration. Initialization means assigning values to the array as it is created.
int scores[5] = {80, 75, 90, 60, 85};
Writing it this way assigns values to each element of the array in order. You can also omit the array size.
int scores[] = {80, 75, 90, 60, 85};  // The number of elements is automatically determined to be 5
Conversely, if you specify the number of elements but provide fewer values, the remaining elements are automatically initialized to 0.
int scores[5] = {80, 75};  // scores[2] through scores[4] become 0

Understanding the Memory Layout of Arrays

In C, the elements of an array are stored contiguously in memory. This property allows efficient manipulation using for loops and pointers. For example, the following code displays all elements of the array in order.
for (int i = 0; i < 5; i++) {
    printf("%d
", scores[i]);
}
Understanding the basic structure of arrays is crucial for the “copy operations” discussed later.
侍エンジニア塾

3. How to Copy Arrays

In C, you cannot copy an entire array using the assignment operator (=). The following code results in a compilation error.
int a[5] = {1, 2, 3, 4, 5};
int b[5];
b = a;  // Error: assigning one array to another is not allowed
Therefore, to copy an array you need either an explicit element‑by‑element copy or using standard library functions. Here we introduce three representative methods.

Copying Elements with a for Loop

The most basic and safe approach is to use a for loop to copy elements one by one.
#include <stdio.h>

int main() {
    int src[5] = {10, 20, 30, 40, 50};
    int dest[5];

    for (int i = 0; i < 5; i++) {
        dest[i] = src[i];
    }

    // Display the copy result
    for (int i = 0; i < 5; i++) {
        printf("%d ", dest[i]);
    }

    return 0;
}
The advantage of this method is that it is easy to understand and control the array size. It is highly safe and recommended for beginners.

memcpy Function for Fast Copy

If you want to copy arrays more efficiently, you can use the memcpy function provided by the standard library <string.h>.
#include <stdio.h>
#include <string.h>

int main() {
    int src[5] = {1, 2, 3, 4, 5};
    int dest[5];

    memcpy(dest, src, sizeof(src));  // Copy the number of bytes in src

    for (int i = 0; i < 5; i++) {
        printf("%d ", dest[i]);
    }

    return 0;
}

memcpy Usage Tips:

  • First argument: destination pointer
  • Second argument: source pointer
  • Third argument: number of bytes to copy (note: not the element count)

Cautions:

  • If the source and destination array sizes differ, there is a risk of buffer overflow, so always verify the sizes.
  • Do not use it when the memory regions overlap (explained in the next section).

Differences and When to Use memmove

There is a function similar to memcpy, namely memmove. The difference between them is the behavior when the source and destination overlap.
  • memcpy: Use when memory does not overlap. Overlap leads to undefined behavior.
  • memmove: Can safely copy even when overlapping.

Example:

char str[] = "ABCDE";

// Overwrite copy from the first character to the second and subsequent characters (overlap)
memmove(str + 1, str, 4);
str[5] = ' ';  // null terminator

printf("%s
", str);  // Output: AABCD

Basic Rule for Choosing:

SituationRecommended Function
Memory does not overlapmemcpy
May overlapmemmove
For most array operations, memcpy is sufficient, but in cases such as string manipulation where a portion of an array is moved, you should use memmove.

4. Copying Strings (char Arrays)

In C, strings are treated as arrays of char type, which differs slightly from arrays of numbers, so you need to be aware of that. String copying has dedicated functions, and unlike binary copies such as memcpy, they have the characteristic of “copying including the terminating null character.”

strcpy Function for Copying Strings

The strcpy function included in the C standard library <string.h> is a convenient function that copies a string up to the null terminator.
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "Hello, world!";
    char dest[50];

    strcpy(dest, src);

    printf("Copy result: %s\n", dest);

    return 0;
}
In this code, the string in src (including its terminator) is copied to dest.

Notes:

  • If the size of dest is too small, it can cause a buffer overflow, so you need to ensure sufficient size.
  • The number of characters copied depends on the length of src.

strncpy for Safe Copying

A function that can be used instead of strcpy is strncpy. It follows the specification of “copying only the specified number of characters,” which makes it safer.
#include <stdio.h>
#include <string.h>

int main() {
    char src[] = "C language";
    char dest[10];

    strncpy(dest, src, sizeof(dest) - 1);  // Keep the last byte for the null terminator
    dest[9] = ' ';  // Explicitly set terminator for safety

    printf("Copy result: %s\n", dest);

    return 0;
}

strncpy Characteristics:

  • Copies only the specified length.
  • If the source is shorter, the remaining part is filled with NULL (implementation-defined).
  • The terminating character is not guaranteed to be added automatically, so explicitly setting it yourself is safer.

Caution When Handling Japanese (Multibyte Strings)

When dealing with Japanese and other multibyte characters (UTF-8, Shift-JIS, etc.), using strcpy or strncpy can truncate bytes in the middle, leading to garbled text or display errors. For example, copying only 3 bytes of “Hello” can leave it in a broken state. In such cases, you should consider using libraries that operate on whole characters or using wide characters (wchar_t).

Summary of Best Practices for String Copying

FunctionFeatureCaution
strcpyCopies up to the terminating null characterMust verify buffer size
strncpyCan copy only the specified lengthTerminating character may not be guaranteed
memcpyCan copy arbitrary byte sequencesBinary copy; not suitable for strings
strdupAllocates new memory for the copied string (non-standard)Requires free after use

5. Precautions When Copying Arrays

Copying arrays may seem like a simple operation at first glance, but if not handled correctly it can cause serious bugs and security holes. This section explains the key points to watch out for when copying arrays in C.

Beware of Buffer Overflows

The most common mistake is a “buffer overflow”, where data is written beyond the size of the destination array.

Example: Dangerous Copy Operation

char src[] = "This is a long string.";
char dest[10];

strcpy(dest, src);  // Copy exceeds dest size → potential memory corruption
Such code can cause access to invalid memory regions, leading to program crashes or vulnerabilities.

Countermeasures:

  • strncpy or memcpy should be used, always limiting the size.
  • Remember to manually add the terminating null character.
  • Manage array sizes using constants or macros.

Accurately Determine the Size of the Copy Target

When copying with memcpy or memmove, you need to specify the size in bytes rather than element count.

Example of Safe Size Specification:

int src[5] = {1, 2, 3, 4, 5};
int dest[5];

memcpy(dest, src, sizeof(src));  // specify the total byte size of src
By using sizeof(src) like this, you automatically obtain the total size of the array (in bytes), making it safe. However, when an array is passed as a function argument, sizeof does not work as expected (the array decays to a pointer), so you need to be careful.

Cautions When Working with Pointers

In C, arrays are often treated as pointers, and incorrect pointer operations can corrupt memory.

Common Mistake Example:

int *src = NULL;
int dest[5];

memcpy(dest, src, sizeof(dest));  // using a NULL pointer as source → crash

Key Points:

  • Check that the pointer references a valid address, performing a NULL check.
  • If copying after memory allocation (e.g., malloc), verify the consistency between allocated size and copy size.

Handling Overlapping Source and Destination Regions

As explained earlier, memcpy does not support copying overlapping memory regions. When copying part of an array to another location, using memmove is the rule.
char buffer[100] = "example";

// move a portion of the string within itself
memmove(buffer + 2, buffer, 4);  // safely copy overlapping data

Defining and Managing Array Sizes

For safe copy operations, centralized management of array sizes is effective. Defining them with macros as shown below improves code maintainability and safety.
#define ARRAY_SIZE 10

int arr1[ARRAY_SIZE];
int arr2[ARRAY_SIZE];

memcpy(arr2, arr1, sizeof(arr1));

Summary for Safe Array Copying

  • When copying, accurately determine the size (in bytes).
  • Choose safe functions such as strncpy or memmove.
  • Always verify the size consistency between source and destination.
  • Be especially careful with pointer operations, performing NULL checks and bounds checks.

6. FAQ (Frequently Asked Questions)

In C, we explain in Q&A format the points that beginners to intermediate programmers often wonder about when copying arrays. Understanding the subtle differences and specifications correctly also leads to bug prevention and improved code quality.

Q1. What is the difference between memcpy and memmove?

A. The safety of operation differs when the memory regions overlap.
Comparison Itemmemcpymemmove
Safety for overlapping× (may result in undefined behavior)◎ (uses an internal temporary buffer)
PerformanceFast (low overhead)Slightly slower (safety measures present)
Use caseComplete array copy, etc.Data movement within the same array, etc.
Note: If you know there is no overlap, memcpy is fine, but when in doubt, choosing memmove is safer.

Q2. What are the differences between strcpy and strncpy, and how should they be used?

A. Because there is a trade‑off between safety and flexibility, you need to choose appropriately.
  • strcpy(dest, src) → Copies everything up to the terminating null of src. However, if dest is too small, a buffer overflow can occur.
  • strncpy(dest, src, n) → Copies at most the specified maximum number of bytes n. Safety is higher, but null termination is not guaranteed automatically.
Recommended usage:
  • If you are certain the size is sufficient, use strcpy
  • When safety is paramount or handling arbitrary strings, use strncpy and manually add the null terminator

Q3. Are there any cautions when passing an array as a function argument?

A. Arrays decay to pointers, so you can no longer obtain their size with sizeof.
void copy_array(int arr[], int size) {
    printf("%zu\n", sizeof(arr));  // ← becomes the size of a pointer (e.g., 8)
}
Thus, because the actual size of the array cannot be obtained, the basic practice is to pass the size as an additional argument when passing the array to a function.
void copy_array(int arr[], int size) {
    for (int i = 0; i < size; i++) {
        // processing logic
    }
}

Q4. Is it okay to copy an array of structs with memcpy?

A. Generally it works, but you need to be careful with structs that contain pointers. memcpy performs a binary‑level copy, so if a struct contains pointers, the data pointed to (the actual data) is not copied.

Example (results in a shallow copy):

typedef struct {
    char *name;
    int age;
} Person;

Person a[3];
Person b[3];

memcpy(b, a, sizeof(a));  // copies the pointers themselves (the pointed-to data is shared)
In such cases, double frees or inconsistencies can occur. As a countermeasure, you need to deep‑copy the pointer members individually using malloc + strcpy, etc.

Q5. I want to copy arrays in bulk, but writing a for loop each time is tedious. Can I make a common function?

A. Yes, turning it into a function improves reusability and makes the code cleaner.
void copy_int_array(int *dest, int *src, int size) {
    for (int i = 0; i < size; i++) {
        dest[i] = src[i];
    }
}
In this way, by creating generic copy functions for each type and use case, development efficiency and readability improve.

7. Summary

In this article, we have systematically covered array copying in C, from basics to advanced applications. Finally, we will recap the important points and summarize for real‑world use.

Array copying basics: safety and clear purpose

In C, you cannot assign one array to another directly using =. Therefore, copying requires explicit handling.
  • for loop: the most basic and straightforward. You need to specify the array size.
  • memcpy: fast copy at the binary level. Be careful of size mismatches.
  • memmove: use when source and destination overlap.
  • strcpy / strncpy: functions for strings (char arrays). Choose based on safety considerations.

Safe copying requires proper size management

  • Array size overruns (excessive copying) can cause crashes and vulnerabilities.
  • Using sizeof() to determine the exact number of bytes is important.
  • When handling arrays in functions, understand that they decay to pointers and pass the size as an argument as well.

Understand common pitfalls

  • strncpy is safe but may not null‑terminate, so get into the habit of adding the terminator manually.
  • Arrays that contain pointers to structs may not be correctly copied with memcpy.
  • When dealing with multibyte strings (e.g., Japanese), be aware of the difference between character count and byte count.

Applying it in practice

  • If array copying occurs frequently in a project, it’s useful to create a dedicated utility function.
  • Copy operations are a well‑isolated unit for testing, so verifying safety with unit tests is recommended.

Finally

Because C is a low‑level language, even a single array copy can be deep. However, once you grasp the basic knowledge and techniques presented here, you’ll be able to apply them in a variety of scenarios. Use this article as a reference to master “correct and safe copy operations” and create more reliable C programs.