Что приводит к сбою этого переназначения целочисленного указателя?

StackOverflow https://stackoverflow.com/questions/207800

  •  03-07-2019
  •  | 
  •  

Вопрос

Я новичок в C, и у меня есть этот вопрос.почему происходит сбой следующего кода:

int *a = 10;
*a = 100;
Это было полезно?

Решение

Потому что вы пытаетесь записать 100 в ячейку памяти 0x0000000A, которая, вероятно, не выделена для вашей программы.То есть,

int *a = 10;

не означает, что указатель «а» будет указывать на место в памяти, имеющее значение 10.Это означает, что он указывает на адрес 10 (0x0000000A) в памяти.Затем вы хотите что-то записать по этому адресу, но у вас нет на это «прав», поскольку он не выделен.

Вы можете попробовать следующее:

int *a = malloc(sizeof(int));
*a = 100;

Это сработает, хотя и ужасно неэффективно.Если вам нужен только один int, вам следует просто поместить его в стек, а не куча.В 32-битной архитектуре указатель имеет длину 32 бита, а длина int также составляет 32 бита, поэтому ваша структура указателя на int занимает (по меньшей мере) Таким образом, 8 байт памяти вместо 4.И мы даже не упомянули проблемы с кэшированием.

Другие советы

Вам нужно присвоить указатель ячейка памяти, а не произвольное значение (10).

int cell = 10;
int *a = &cell; // a points to address of cell
*a = 100;       // content of cell changed

Видеть мой ответ на другой вопрос, об осторожности с С.

Я хотел бы предложить небольшое изменение в использовании malloc() для всех ответов, в которых предлагается использовать его для выделения памяти для int.Вместо:

a = malloc(sizeof(int));

Я бы посоветовал не повторять тип переменной, поскольку он известен компилятору, а повторение его вручную делает код более плотным и увеличивает риск ошибки.Если вы позже измените объявление, например, на.

long *a;

Не изменив распределение, вы в конечном итоге выделите неправильный объем памяти (в общем случае на 32-битных машинах). int и long часто имеют одинаковый размер).ИМО, лучше использовать:

a = malloc(sizeof *a);

Это просто означает «размер типа, на который указывает a», в данном случае int, что, конечно, совершенно верно.Если вы измените тип в объявлении, как указано выше, эта строка все равно будет правильной.Риск по-прежнему существует, если вы измените имя переменной в левой части присваивания, но, по крайней мере, вы больше не будете повторять информацию без необходимости.

Также обратите внимание, что скобки не нужны при sizeof при использовании его на реальных объектах (т.е.переменные), только с именами типов, которые выглядят как выражения приведения. sizeof это не функция, это оператор.

Потому что вы никогда не выделяли память для a.Вы только что выделили место в стеке для указателя на a.

int *a = NULL;

a = malloc (sizeof (int));

if (a != NULL)
{
*a =10;
}

Будет работать.

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

то есть

int a* = NULL;
int b = 10;

a = &b;

Теперь это будет означать, что выполнение чего-то вроде

*a = 100;

также установит b равным == 100

Посмотрите это:http://home.netcom.com/~tjensen/ptr/pointers.pdf

Следующая строка,

int *a = 10;

определяет указатель на целое число а.Ты тогда точка указатель a на ячейку памяти 10.

Следующая строка,

*a = 100;

Помещает значение 100 в ячейку памяти, на которую указывает a.

Проблема в:

  1. Вы не знаете, куда указывает.(Вы не знаете значение ячейки памяти 10)
  2. Куда бы ни указывал a, вы, вероятно, не имеете права изменять это значение.Вероятно, это память какой-то другой программы/процесса.Ты вор!

Поскольку вы объявляете указатель на int, инициализируйте указатель до 10 (адрес), а затем попытайтесь присвоить значение int по этому адресу.Поскольку память по адресу 10 не принадлежит вашему процессу, вы получаете сбой.Это должно работать:

int *a;
a = malloc(sizeof(int));
*a = 10;
printf("a=%i\n", *a);
free(a);

Этот код вообще компилируется?10 не конвертируется в int *, если только вы не примените его так:

int *a = (int *) 10;
*a = 100;

В этом случае вы пытаетесь записать 100 в адрес памяти по адресу 10.Обычно это неверный адрес памяти, поэтому ваша программа выходит из строя.

Вероятно, происходит сбой, потому что вы назначаете указатель на какую-то часть памяти, к которой у вас нет доступа, а затем присваиваете этому участку памяти какое-то значение (что вам не разрешено делать!).

Вы также можете написать это как:

int* a = 10;
*a = 100;

Обратите внимание на разный интервал в первой строке.Это не популярный стиль, но лично мне кажется, что он более понятен.Для компилятора это имеет точно такое же значение.

Затем прочитайте вслух:

"Pointer-to-int 'a' becomes 10"
"Value-pointed-to-by 'a' becomes 100"

Подставляя фактическое значение:

"Value-pointed-to-by 10 becomes 100"

...после чего вы понимаете, что 10 вряд ли будет указывать на часть памяти, которую вы можете использовать.

Вы практически никогда не назначали бы указатель с литералом:

int* ptr = (int*)10;  // You've guessed at a memory address, and probably got it wrong
int* ptr = malloc(sizeof(int)); // OS gives you a memory address at runtime  

Я думаю, там могут быть некоторые очень задания низкого уровня, в которых вы напрямую указываете абсолютные адреса памяти.Например, реализация ядра?

Хорошо, сегодня я попытаюсь дать самое простое объяснение и в то же время попытаюсь дать вам более подробную картину обо всем этом.Давайте добавим скобки?

(int*) a = 10;
(*a) = 100;

Вы пытаетесь записать четыре байта в диапазон адресов [10-13].Расположение памяти вашей программы обычно начинается выше, поэтому ваше приложение случайно не перезаписывает что-либо из того места, где оно могло бы работать (например, из .data, .bss и стека).Вместо этого он просто выходит из строя, потому что диапазон адресов не был выделен.

Указатель указывает на ячейку памяти, а статическая типизация C определяет тип указателя.Хотя вы можете легко переопределить указатель.Просто:

(void*) v = NULL;

Здесь мы идем дальше к делу.Что такое нулевой указатель?Это просто указатель, указывающий на адрес 0.

Вы также можете указать тип структуры для вашего указателя:

struct Hello {
    int id;
    char* name;
};

...

struct Hello* hello_ptr = malloc(sizeof Hello);
hello_ptr->id = 5;
hello_ptr->name = "Cheery";

Хорошо, что такое malloc?Malloc выделяет память и возвращает указатель на выделенную память.Он имеет следующую сигнатуру типа:

void* malloc(size_t size);

Если у вас нет консервативного сборщика мусора, вполне вероятно, что ваша память не будет освобождена автоматически.Поэтому, если вы хотите снова использовать память из того, что вы только что выделили, вы должны сделать:

free(hello_ptr);

В каждом создаваемом вами malloc есть тег размера, поэтому вам не нужно указывать размер фрагмента, который вы указали для бесплатной процедуры.

Хорошо, и еще один вопрос: как выглядит строка символов в памяти?Например, тот, что похож на «Cheery».Простой ответ.Это массив байтов с нулевым завершением.

0.1.2.3.4.5. 6
C h e e r y \0
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top