Сомнительная инициализация указателя - PullRequest
4 голосов
/ 06 января 2011

Мы могли бы инициализировать указатель символа, как это в C.

char *c="test";

Где c указывает на первый символ (t).

Но когда я дал код, как показано ниже. Это дает ошибку сегментации.

#include<stdio.h>
#include<stdlib.h>
main()
{

    int *i=0;
    printf("%d",*i);
}

Также, когда я даю

#include<stdio.h>
#include<stdlib.h>
main()
{
    int *i;
    i=(int *)malloc(2);
    *i=0;
    printf("%d",*i);
}

Сработало (выдал вывод 0).

Когда я дал malloc(0), это сработало (выдало вывод 0).

Пожалуйста, расскажите, что происходит

1 Ответ

5 голосов
/ 06 января 2011

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

int *i=0;

Вы не можете отменить ссылку на указатель, который ни на что не указывает и ожидает хороших событий. =)

Второй сегмент кода работает, потому что вы фактически назначили память для вашего указателя, используя malloc, который вы можете удалить из ссылки. Я думаю, что вы можете получить значения, отличные от нуля, в зависимости от памяти рядом с адресом, который вы выделили с помощью malloc. Я говорю это потому, что обычно значение int составляет 4 байта, а вы присваиваете только 2. При разыменовании указателя int он должен возвращать значение в виде int на основе указанных 4 байтов. В вашем случае, первые 2 байта - это то, что вы получили от malloc, а смежные 2 байта - все, что есть, что угодно, и что бы это ни было, будет обрабатываться, как если бы оно было int. Вы можете получить странное поведение, подобное этому, и вам следует распределить размер памяти, необходимый для типа, на который вы пытаетесь использовать / point.
(т.е. int *i = (int *) malloc(sizeof(int));)

Если у вас есть указатель, указывающий на память правильного размера, вы можете установить следующие значения:

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

int main (int argc, char *argv[])
{
    int *i = (int *)malloc(sizeof(int));
    *i = 25;
    printf("i = %d\n",*i);

    *i = 12;
    printf("i = %d\n",*i);
    return 0;
}

Редактировать на основании комментария:

Указатель указывает на память, а не на значения. При инициализации char *ptr="test"; Вы не присваиваете значение «test», вы назначаете адрес памяти, где компилятор помещает «test», который помещается в сегмент данных вашего процесса и доступен только для чтения. Если вы попытаетесь изменить строку «test», то, скорее всего, вы запрограммируете seg-fault. Что вам нужно понять о char *, так это о том, что он указывает на один (то есть первый) символ в строке. Когда вы отменяете ссылку на символ *, вы увидите только 1 символ и один символ. C использует строки, оканчивающиеся нулем, и обратите внимание, что вы не отменяете ссылку на ptr при вызове printf, вы передаете ему сам указатель, и он указывает только на первый символ. Как это отображается, зависит от формата, переданного в printf. Когда printf передается в формате «% c», он будет печатать односимвольные точки ptr, если вы передадите формат «% p», он напечатает адрес, на который указывает ptr. Чтобы получить всю строку, вы передаете '% s' в качестве формата. Это заставляет printf начинать с указателя, который вы передали, и читать каждый последующий байт, пока не будет достигнут ноль. Ниже приведен код, демонстрирующий это.

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

int main (int argc, char *argv[])
{
    // Initialize to data segement/read only string
    char *ptr = "test";
    printf("ptr points at     = %p\n", ptr);   // Prints the address ptr points to
    printf("ptr dereferenced  = %c\n", *ptr);  // Prints the value at address ptr
    printf("ptr value         = %s\n", ptr);   // Prints the string of chars pointed to by ptr

    // Uncomment this to see bad behavior!
    // ptr[1] = 'E'; // SEG FAULT -> Attempting to modify read-only memory

    printf("--------------------\n");

    // Use memory you have allocated explicitly and can modify
    ptr = malloc(10);
    strncpy(ptr, "foo", 10);
    printf("ptr now points at = %p\n", ptr);   // Prints the address ptr points to
    printf("ptr dereferenced  = %c\n", *ptr);  // Prints the value at address ptr
    printf("ptr value         = %s\n", ptr);   // Prints the string of chars pointed to by ptr

    ptr[1] = 'F';  // Change the second char in string to F
    printf("ptr value (mod)   = %s\n", ptr);
    return 0;
}
...