#c #pointers #memory-address
#c #указатели #адрес памяти
Вопрос:
Я вызываю функцию, которая меняет местами сдвиги массажа в памяти:
for (int i = now->size - 1; i >= 0; i--)
{
void *address2 = prev->start_address i;
void *address1 = now->start_adress i;
address1 = address2;
address2 = '';
}
Итак, в основном у меня есть два адреса, один из которых указывает на первое начальное местоположение, а другой — на второе начальное местоположение, в которое необходимо вставить содержимое.
Проблема в том, что единственное решение, которое я нахожу, — это добавить int
(это значение i) и prev->start_adress
(это void *), как я показал. Я хочу сделать это правильно, я не могу изменить указатель void на int. Есть ли какие-либо другие возможности.
Мои ошибки:
error: invalid conversion from ‘void*’ to ‘char*’ [-fpermissive]
warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arit]
214 | void *address2 = prev->start i;
Warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arit]
215 | void *address1 = now->start i;
Вспомогательная информация:
У меня есть связанный список (полный segementdescriptors) и «память», представляющая собой простой массив [].Аналогично тому, как работает malloc.
typedef struct segmentdescriptor
{
Byte allocated;
void *start;
size_t size;
struct segmentdescriptor *next;
} Node;
начальные указатели указывают на начало выделенного пространства в массиве[].
Обновление: самый простой способ — использовать typecast для выполнения арифметики с указателями void, если вы знаете их размер, например :
char *address2 = (char *)prev->start i;
Если вы не знаете тип, это невозможно, потому что, например:
char *pointer
указывает на один байт памяти, и если вы пишете pointer
, переходит
к следующему байту. int *pointer
допустим, указывает четыре раза. если вы пишете pointer
, переходит к четырем байтам после четырех байтов.
Ниже также есть хорошие ответы. Спасибо за все ответы.
Комментарии:
1. Вы не можете выполнять арифметику с void *. Как он узнает, сколько нужно добавить?
2. «я не могу изменить указатель void на int» почему? вы должны иметь возможность преобразовать его в
int
(или любой другой целочисленный тип данных, который способен удерживать указатель без потери данных), а затем преобразовать его обратно вvoid*
3. start_adress указывает на первый адрес в памяти, который необходимо скопировать
4. Обычным решением является приведение
void*
кchar*
.5.
void *address1 = now->start_adress i;
но вы отбрасываете присвоенное значение при следующем присваиванииaddress1 = address2;
, и что вaddress2 = '';
этом говорит о том, что вы намерены присвоить значение char переменной указателя. Я думаю, вы пропустили несколько операторов разыменования. Рассматривали ли вы возможность использованияmemcpy
ormemmove
?
Ответ №1:
Я не совсем понимаю, что shifts a massage in memory
это такое, но если вы просто хотите скопировать одну ячейку памяти в другую, вы можете
-
Используйте
memcpy
илиmemmove
(если ячейки памяти перекрываются)memcpy(now->start_adress, prev->start_address, now->size);
-
Напишите свою собственную функцию для копирования памяти
void *mymemcpy(void *dest, const void *src, size_t size)
{
unsigned char *cdest = (unsigned char *)dest; //cast for C compiler
const unsigned char *csrc = (unsigned char *)src;
while(size--) *cdest = *csrc;
return dest;
}
void *mymemcpy(void *dest, const void *src, size_t size)
{
unsigned char *cdest = (unsigned char *)dest; //cast for C compiler
const unsigned char *csrc = (unsigned char *)src;
for(size_t index = 0; index < size; index ) cdest[index] = csrc[index];
return dest;
}
void *mymemcpy(void *dest, const void *src, size_t size)
{
unsigned char *cdest = (unsigned char *)dest; //cast for C compiler
const unsigned char *csrc = (unsigned char *)src;
for(size_t index = 0; index < size; index ) *(cdest index) = *(csrc index);
return dest;
}
Стандарт C не допускает никакой арифметики указателей на void
указатели. gcc
имеет расширение, которое обрабатывает указатель void *
as на char, разрешающий арифметику, но не допускающий разыменования.
Комментарии:
1. в первой версии
mymemcpy()
вы забыли увеличитьcsrc
Ответ №2:
Тип void
всегда является неполным типом. То есть размер объекта типа void
неизвестен. Таким образом, вы не можете использовать арифметику указателя с указателем типа void *
, хотя некоторые компиляторы имеют свои собственные языковые расширения, которые позволяют выполнять арифметику указателя с типом void *
так же, как с указателями типа char *
.
Итак, эти утверждения
void *address2 = prev->start i;
void *address1 = now->start i;
неверны в соответствии со стандартом C, поскольку указатель start
имеет тип void *
.
Также кажется, что эти утверждения
address1 = address2;
address2 = '';
вы делаете не то, что вы делаете.
Для начала это утверждение
address1 = address2;
присваивает один указатель другому указателю, хотя похоже, что на самом деле вы хотите присвоить значение, на которое указывает один указатель, памяти, на которую указывает другой указатель.
И это утверждение эквивалентно
address2 = NULL;
То есть он не устанавливает указанную память с завершающим нулевым символом ''
.
Если, как вы говорите, эти указатели имеют дело с сообщением (строкой), тогда вам нужно привести указатели к типу char *
.
Что касается этой вашей фразы
Я вызываю функцию, которая меняет местами сдвиги массажа в памяти:
тогда совершенно непонятно, что вы пытаетесь сделать, используя цикл for, потому что цикл в любом случае не имеет смысла.
Если вам нужно скопировать один массив символов в другой массив символов, используйте стандартную функцию C memcpy
или memmove
в зависимости от того, что и как вы пытаетесь скопировать массивы.
Ответ №3:
Что касается этих предупреждений:
warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arit]
214 | void *address2 = prev->start i;
Warning: pointer of type ‘void *’ used in arithmetic [-Wpointer-arit]
215 | void *address1 = now->start i;
На любом современном компьютере значением указателя является адрес памяти (обычно адрес виртуальной памяти). Когда вы добавляете единицу к указателю, его значение (иначе адрес памяти) увеличивается на размер указываемого типа.
Пример:
TYPE* p = SOME_ADDRESS; // The value of p is now SOME_ADDRESS
p = p 1; // The value of p is now SOME_ADDRESS sizeof(TYPE);
p = SOME_ADDRESS; // The value of p is now SOME_ADDRESS
p = p i; // The value of p is now SOME_ADDRESS i * sizeof(TYPE);
Другими словами: чтобы добавить целочисленное значение к указателю, нам нужно знать размер элемента, на который указывает указатель.
И это ваша проблема. У вас есть указатели void, поэтому вам нужно будет знать «sizeof void», чтобы обновить указатель. Но sizeof void может быть любым и не определяется стандартом. По-видимому, ваш компилятор имеет нестандартное расширение, которое позволяет sizeof(void)
. Следовательно, ваш компилятор выдает вам только предупреждение.
Что касается этой ошибки:
error: invalid conversion from ‘void*’ to ‘char*’
Это происходит из какого-то сообщения кода, которое вы не публиковали. Далее это показывает, что вы используете компилятор c вместо компилятора c.
Наконец: даже если арифметика указателя была действительной, ваш код ничего не делает.
for (int i = now->size - 1; i >= 0; i--)
{
void *address2 = prev->start_address i;
void *address1 = now->start_adress i;
address1 = address2; // This only change the value of the pointer
// It doesn't change the memory that the
// pointer points to
address2 = '';
}
Не совсем понятно, что вы пытаетесь сделать, но, возможно, это то, что вы ищете:
for (int i = now->size - 1; i >= 0; i--)
{
char *address2 = (char*)prev->start_address i;
char *address1 = (char*)now->start_adress i;
*address1 = *address2;
*address2 = '';
}
Комментарии:
1. Не имеет значения, как хранится указатель и как указатель представлен реализацией. Арифметика указателя не зависит от этого.
2.
Consequently, your compiler gives you a warning.
в этом случае компилятор точно не знает, как это работает, потому что это компилятор семейства gcc.3. @P__JsupportswomeninPoland Наверняка это не так, но обработка указателей как адресов памяти помогает объяснить, почему все так, как есть. И все современные системы работают так.
4. Указатель arthmetic определяется только для одного и того же массива. Достаточно использовать термин элемент массива, чтобы объяснить, как это работает.