Законно ли передавать указатель без длины в качестве места назначения в memcpy? - PullRequest
1 голос
/ 07 февраля 2020

Я хотел бы знать, могу ли я использовать указатель на символ без длины в качестве места назначения в memcpy. Пример: я хочу скопировать данные из массива char определенной длины с определенным размером в другой массив, но я бы хотел определить его как указатель без определенного размера.

char * ptr_1;
char arr[4] = "Data";
memcpy(ptr_1, arr, 4); // IS it allowed to do this?

Ответы [ 2 ]

4 голосов
/ 07 февраля 2020

Нет, вы не можете этого сделать. Если вы сделаете это, это вызовет неопределенное поведение, так как адрес, указанный ptr_1, находится в определителе, и вы не являетесь его владельцем. Более того, вы не выделили никакой памяти для хранения содержимого из arr.

. Вы можете выделить статическое хранилище c для копирования результата или динамически выделить хранилище. Прототипом для memcpy() является

void *memcpy( void *dst, void const *src, size_t length );

Так что для статически выделенного адреса вы можете сделать что-то вроде

#include <stdio.h>

int main(void) {
    char temp[5];
    char values[] = "Data";
    memcpy( temp, values, 4 );
    temp[4] = '\0';
    printf("%s\n", temp);
    return 0;
}

или с динамически распределенным хранилищем, на которое указывает ptr хранения 4 char байтов

#include <stdio.h>
#include <stdlib.h>

#define SIZE 4

int main(void) {
    char *ptr;
    char values[] = "Data";
    ptr = malloc(sizeof(char) * (SIZE+1)); 
    if ( ptr == NULL ) return; 
    memcpy(ptr, values, SIZE);
    ptr[SIZE] = '\0';
    printf("%s\n", ptr);
    return 0;
}

Хотя прототип для memcpy() определяет использование void * для типов источника и назначения, стандарт C не предписывает его. Указатели могут быть преобразованы из любого типа в void * и наоборот. По этой причине мы не рассматриваем также результат malloc().

Вам всегда нужно выделять память, чтобы в конце включить нулевой символ. Если вы инициализируете массив пустым спецификатором длины, т. Е. Как values[], компилятор автоматически выделяет хранилище для включения нулевого символа в конце. Для библиотечной функции, такой как printf(), для печати строки в идеале можно ожидать, что строка будет завершена нулевым символом в конце. Его отсутствие может вызвать неопределенное поведение, так как он не знает, где находится конец строки (нулевой символ). Таким образом, в обоих случаях убедитесь, что последний байт строки является нулевой символьной константой.

3 голосов
/ 07 февраля 2020

ptr_1 - указатель, указывающий на что-либо, и выполнение memcopy в произвольном месте приводит к неопределенному поведению.

указатель должен быть назначен действительному адресу до вызова memcopy.

Как это,

char buf[4];
char * ptr_1 = buf;
char arr[4] = "Data";
memcpy(ptr_1, arr, 4); 

enter image description here

...