-6

I was exploring memcpy in C++. I have a program that reads 10 bytes from a file called temp.txt. The content of the file is:

abcdefghijklmnopqrstuvwxyz

Here's the code:

// This file is called "temp.cpp"

#include <string>
#include <fcntl.h>
#include <iostream>
#include <unistd.h>

int main() {
    int fd = open("temp.txt", O_RDONLY);
    int buffer_size{10};
    char buffer[11];
    char copy_buffer[11];
    std::size_t bytes_read = read(fd, buffer, buffer_size);
    std::cout << "Buffer: " << buffer << std::endl;
    printf("Buffer address: %p, Copy Buffer address: %p\n", &buffer, &copy_buffer);
    memcpy(&copy_buffer, &buffer, 7);
    std::cout << "Copy Buffer: " << copy_buffer << std::endl;
    return 0;
}

I read 10 bytes and store them (and \0 in buffer). I then want to copy the contents of buffer into copy_buffer. I was changing the number of bytes I want to copy in the memcpy() function. Here's the output:

memcpy(&copy_buffer, &buffer, 5); // abcde
memcpy(&copy_buffer, &buffer, 6); // abcdef
memcpy(&copy_buffer, &buffer, 7); // abcdefg
memcpy(&copy_buffer, &buffer, 8); // abcdefgh?C??abcdefghij

I noticed that the last output is weird. I tried printing the addresses of copy_buffer and buffer and here's what I got:

Buffer address: 0x16cf8f5dd, Copy Buffer address: 0x16cf8f5d0

Which means, when I copied 8 characters, copy_buffer did not terminate with a \0, so the cout went over to the next addresses until it found a \0. This explains the entire buffer getting printed since it has a \0 at its end.

Why doesn't the same happen when I memcpy() 5, 6, 7 bytes? Is it because there's a \0 at address 0x16cf8f5d7 which gets overwritten only when I copy 8 bytes?

10
  • 11
    and \0 in buffer - no, you don't do that. Your program exhibits undefined behavior, and the question "why doesn't the same happen...?" is unanswerable, because everything can happen. Commented Apr 10 at 21:42
  • 1
    Welcome to dumb luck. Those buffers happened to contain enough null characters for you to be fooled into thinking things were working except for some odd cases when in fact nothing was truly working. Commented Apr 10 at 22:00
  • 1
    This is memcpy not strcpy. It copies memory, exactly as many bytes as you tell it to. If you want a null terminator, you need to write it into the buffer yourself. But you don't need to use memcpy, if you're fine with std::cout then you're fine with std::string. The purpose of memcpy is in very low-level code or when you can't use std::copy/copy_n for some reason. Why are you trying to do things this way? Commented Apr 11 at 0:03
  • 1
    I recommend learning to use a debugger. See What is a debugger and how can it help me diagnose problems?. Commented Apr 11 at 4:21
  • 1
    If you remove the std::cout from this snippet, it becomes pure C. So, you'd better tag C instead of C++. Otherwise, memcpy and raw arrays are not the goto in C++. C++20 preferred types for void buffers are std::array<std::byte, N> and std::vector<std::byte> both of which can use data(buffer) and size(buffer) via ADL, or their member counterparts(buffer.size(), buffer.data()). For resource safety, I would wrap fd in some RAII class, before proceeding. Commented Apr 11 at 8:35

1 Answer 1

0

Why doesn't the same happen when I memcpy() 5, 6, 7 bytes? Is it because there's a \0 at address 0x16cf8f5d7 which gets overwritten only when I copy 8 bytes?

Well, yes. When you declare a variable with no initial value, literally anything could be stored within it. Since you didn't initialize copy_buffer with 0s, it is undefined behaviour and you simply got lucky enough for it not to matter when you copied 5, 6, or 7 bytes, but it eventually happened when you copied 8 bytes.

The easiest solution is for you to use strncpy instead of memcpy, so the null character is either copied or created depending of the size you're asking for it to copy.

Alternatively, you can memset the whole copy_buffer array to 0.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.