2017-02-05 6 views
1

Я могу «упаковать» массивы длинной строки. Теперь, если я memcpy строку, содержащую массивы длинные, содержимое теряется. Здесь у вас есть мой код:Копирование строк с длинными

#include <stdio.h> 
#include <string.h> 

int main() 
{ 
    unsigned char arr[40]; 
    unsigned char arr2[40]; 
    unsigned int i = 0 ; 
    long f=0; 

    for (i = 0 ; i < 5 ; i++) { 
     f = i + 1 ; 
     *((long *)arr + i*sizeof(long)) = f ; 
    } 
    memcpy(arr2, arr, 40); 
    for (i = 0 ; i < 5 ; i++) { 
     f = *((long *)arr2 + i*sizeof(long)) ; 
     printf("f =%ld from arr2 sizeof %zu\n", f, (size_t)(i*sizeof(long))); 
    } 
    for (i = 0 ; i < 5 ; i++) { 
     f = *((long *)arr + i*sizeof(long)) ; 
     printf("f =%ld from arr sizeof %zu\n", f, (size_t)(i*sizeof(long))); 
    } 
} 

И это выход:

f =1 from arr2 sizeof 0 
f =0 from arr2 sizeof 8 
f =1 from arr2 sizeof 16 
f =140734674541394 from arr2 sizeof 24 
f =140734674541702 from arr2 sizeof 32 
f =1 from arr sizeof 0 
f =2 from arr sizeof 8 
f =3 from arr sizeof 16 
f =4 from arr sizeof 24 
f =5 from arr sizeof 32 

Как вы можете видеть, я могу читать длинные значения, которые я сделал в магазине «аранжировка», но не из " arr2" . Любая подсказка?

+3

'я * SizeOf (длинный)' -> 'i' – BLUEPIXY

+2

' (long *) arr2 + i * sizeof (long) 'приведет к неопределенному поведению из-за отсутствия доступа к буферу. '(long *) arr2 + i' уже индексируется в' sizeof (long) ' – StoryTeller

+1

Спасибо ** все ** за ваши ответы и комментарии. К сожалению, я могу принять только один из них ... – mauro

ответ

1

При добавлении 1 указателю p и sizeof(*p) == 8, это эквивалентно добавлению 8 к char указателя. Другими словами, после того, как вы указали указатель, больше не нужно масштабировать индекс.

#include <stdio.h> 
#include <string.h> 

int main() 
{ 
    unsigned char arr[40]; 
    unsigned char arr2[40]; 
    unsigned int i = 0 ; 
    long f=0; 

    for (i = 0 ; i < 5 ; i++) { 
     f = i + 1 ; 
     *((long *)arr + i) = f ; 
    } 
    memcpy(arr2, arr, 40); 
    for (i = 0 ; i < 5 ; i++) { 
     f = *((long *)arr2 + i) ; 
     printf("f =%ld from arr2 sizeof %zu\n", f, (size_t)(i*sizeof(long))); 
    } 
    for (i = 0 ; i < 5 ; i++) { 
     f = *((long *)arr + i) ; 
     printf("f =%ld from arr sizeof %zu\n", f, (size_t)(i*sizeof(long))); 
    } 
} 

Технически, хотя, программа по-прежнему неопределенные, поскольку это нарушает строгого сглаживание. Вы можете решить это, используя массив long и доступ к нему с помощью указателя char, используя динамическую память вместо массивов, распределенных по стекам, или путем memcpying char байтов во временную длину каждой итерации цикла (gcc может принимать намек, и последнее решение не становится вообще неэффективным, несмотря на то, что похоже на кажущийся дорогостоящий вызов функции).

+0

@StoryTeller Ну, вот что я предложил в качестве решения. Вышеупомянутая программа, однако, нарушает строгий псевдоним (сначала в '* ((long *) arr + i) = f;'), потому что он использует длинный указатель для доступа к массиву символов, а не наоборот. – PSkocik

+0

При внимательном прочтении я действительно ошибаюсь. Хотя если массив символов с автоматическим хранилищем по-прежнему желателен, проблема может быть смягчена с помощью типа union-punning, думает я. (значения ловушки не выдерживают, конечно). – StoryTeller

+0

@StoryTeller Иногда я использую alloca (я использую его вместо VLA, потому что тогда я все еще могу перейти через выделение) и притворяться, что это похоже на память malloc'd. – PSkocik

1

Проблема заключается в том, что один ты бросил (гнилые) указатель arr и arr2 к long*, то вы больше не иметь массив О.Б. байт, но массив long так что ваш указатель арифметика больше не быть правильным (это предполагает указатель - указатель char). Бросьте умножение и просто сделайте, например.

*((long *)arr + i) = f ; 
2

(long *)arr2 + i*sizeof(long) приведет к непредсказуемому поведению из-за доступа границы буфера. (long *)arr2 + i уже индексируется в sizeof(long).

Итак, вы пишите путь до конца arr, но копируете только первые 40 байтов. Помимо этого, нет смысла рассуждать о неопределенном поведении. Если бы вам повезло, это бы разбилось, давая немедленное указание, что вы сделали что-то ужасно неправильно.

1

Ваша проблема заключается в нескольких выражений

*((long *)arr + i*sizeof(long)) 

Вы должны решить, будете ли вы делать арифметические операции над указателями на char указателей или long указателей.

Если вы хотите сделать это на char указателей, вы начинаете с arr, добавьте я * SizeOf (длинный), и преобразовать в long указатель:

  arr 
     arr + i*sizeof(long) 
(long *)(arr + i*sizeof(long)) 

С другой стороны, вы можете также конвертировать arr - long указатель в первую очередь.Но потом, вы не должны умножить sizeof(long), потому что арифметика указателей long работает в единицах sizeof(long), а не байт:

  arr 
(long *)arr 
((long *)arr + i) 
Смежные вопросы