2009-08-14 3 views
1

Я говорю в стандарте, K & R C.Различие между указателем инициализациями

Дано:

const char a[] = {1, 2, 3}; 
const char *p = NULL; 

Является ли эти два утверждения эквивалентно:

  1. *p = a;

  2. p = a;

Каждый из них будет находиться на третьей строке фрагмента.

1 и 2, конечно, не выглядят одинаково.

В чем разница между этими двумя тогда?

+0

Btw, это не влияет на ответ, но нет такой вещи, как «Стандарт K & R C». K & R C, описанный в первом издании «Язык программирования C», теперь устарел. Стандарт C поставляется в двух основных вариантах: C89/C90 и C99. C89 также называется «ANSI C», поскольку ANSI опубликован в 1989 году, а затем ISO опубликовал фактически идентичный стандарт в 1990 году. C99 опубликован в другом порядке - сначала ISO, затем ANSI. Второе и третье издания книги K & R относятся к ANSI C, но я не думаю, что это делает «стандартным K & R C» –

ответ

2

Оператор * - это то, что мы называем dereference operator. Чтобы понять, что он делает, вы должны точно понимать, что такое указатель.

Когда вы

char *p; 

«переменный» р не использовать один и тот же объем памяти, как обычный полукокс, он использует больше памяти: она использует объем памяти, необходимый для правильной идентификации позиции памяти на вашем компьютере. Итак, допустим, вы используете 32-битную архитектуру, переменная p занимает 4 байта (а не 1 байт, который вы ожидаете от символа).

Итак, когда вы делаете

p = a; 

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

После выполнения этой строки значение p является адресом памяти массива символов a.

Теперь для оператор разыменования. Когда вы делаете

*p = 'Z'; 

вы сообщаете компилятору, что вы хотите сохранить значение «Z» на адрес, на который указывает р. Таким образом, значение p остается неизменным после этой строки: оно продолжает указывать на тот же адрес. Это значение этого адреса, который изменился и теперь содержит «Z».

Таким образом, конечный эффект

char a[] = {'a', 'b', 'c'}; 
char p = a; 
*p = 'Z'; 

такое же, как изменения первой позиции массива А до «Z», то есть:

char a[] = {'a', 'b', 'c'}; 
a[0] = 'Z'; 

Примечание: есть разница при создании точки указателя на массив: переменная, содержащая массив, содержит только адрес первого элемента, поэтому a - это то же самое, что и «начальный адрес массива».

Обычно вы увидите оператора &. Это оператор, используемый для получения адреса памяти переменной. Например:

int number = 42; 
int pointer = &number; 
printf("%d", *pointer); 

Здесь у нас есть все они. Первая строка создает целочисленную переменную и хранит внутри нее 42.

Вторая строка создает указатель на целое число и сохраняет адрес номер переменной внутри него.

Третья строка считывает значение по адресу, указанному Указатель.

Итак, хитрость заключается в том, чтобы читать * х, как по адресу, указанному на х и & х, как адрес х.

+0

p = a не является ярлыком. Это смутило бы людей больше, чтобы вызвать указатель на массив типа 'p = & a [0]'. – jkeys

4

No.

p = a инициализирует указатель, чтобы указать на что-то другое (как правило, он копирует другой указатель или будет указывать на ссылки, ала p = &a.

*p = a инициализирует, что р относится к. Вы " разыменования "(глядя на), на что указывает p. Если p указывает на NULL, как в вашем примере, вы потерпите крах (это хорошо, вы не хотите случайно получить что-то и повредить свою программу).

В этом case, p = a укажет на первый из array a [], и *p = a попытается изменить первый массив (он не будет работать; вы его объявили const).

Вот небольшой пример программа в C++, с почти идентичным синтаксисом C.

#include <iostream> 

int main() 
{ 
    char arr[5] { 'a', 'b', 'c' }; // arr[3] and arr[4] are set to 0 
    char *ptr = arr; //point to 'a' 

    for (int i = 0; i != 5; i++) 
    { 
     *ptr = 'f'; //this changes the array 
     ptr++; //this changes what the pointer points to; moves it to next in array 
    } 

    for (int i = 0; i != 5; i++) 
    { 
     std::cout << *ptr << " "; 
    } 

    //outputs f f f f f 
} 
+0

»и * p = a попытается изменить первый массив (он не будет работать , вы его объявили const). Небольшая коррекция: p указывает на NULL; a имеет массив. Он разыгрывает NULL, как вы сказали во втором абзаце; не изменяя массив, как вы сказали в третьем. – Tordek

1

Первыми разыменовывает пустой указатель, и пытается присвоить ему адрес массива. Это будет ошибка компилятора, потому что char != char []. Если бы это было не так, это, скорее всего, потерпело крах.

Вторые комплекты p, чтобы указать на массив.

0

Нет, они не эквивалентны

Если p = NULL, то делать *p = a даст вам ошибку сегментации.

0
  1. Потому что «* p» разыгрывает указатель, не делает ли это «p» a «char **»?
  2. Это будет указывать «p» на первый массив, как ожидалось.

Я думаю, что они не совпадают.

1

Вот трюк, который я использовал, когда узнал C (и до сих пор пользуюсь сегодня).

Всякий раз, когда вы видите * перед переменной в своем коде, автоматически читайте ее как «на что указывает».

Итак, вы должны уметь легко видеть, что установка «p» на «a» сильно отличается от установки «на что указывает p» на «a».

Кроме того, поскольку p должен указывать на символ, устанавливающий, что char p указывает на (в настоящее время «char» в ячейке памяти 0, при условии, что null равен 0) указателю на символ (a), вероятно, будет не удается во время компиляции, если вам повезет (в зависимости от ваших настроек компилятора и линта это может действительно наступить.)

from comment: В объявлении функции, например f (char c), я обычно пытаюсь выделить имя переменной из остальной части - так что это будет f ((char) c). поэтому c является char *. Точно так же, как определение переменной.

Также & обычно читается как «Адрес», но это становится еще более опасным. Несколько примеров того, как я читаю вещи себе. Может или не поможет.

int a[] = {1,2,3}; // I mentally parse this as (int[]) a, so a is an int array. 
int *p;   // p is a pointer to "integers" 
int i; 
p=a;    // p acts exactly as a does now. 

i=*p;   // i is "What is pointed to by" p (1) 
i=p;   // i is some memory address 
i=*a;   // i is what is pointed to by a (1) 
i=p[1];  // Don't forget that * and [] syntax are generally interchangable. 
i=a+1;   // Same as above (2). 
p=&i;   // p is the address of i (it can because it's a pointer) 
       // remember from hs algebra that = generally reads as "is", still works! 
*p=7;   // what is pointed to by p (i) is 7; 
a=*i;   // whoops, can't assign an array. This is the only difference between 
       // arrays and pointers that you will have to deal with often, so feel 
       // free to use which ever one you are more comfortable with. 

char c='a'; 
char * d = &c;// d is a char pointer, and it is the address of c 
char ** e ; // e is a pointer to a memory location containing 
       // a pointer to a char! 
e=&d;   // gets d's address. a pointer to a pointer gets 
       // the address of a pointer. Messy but gets the job done 

**e=5;   // what is pointed to by what is pointed to by e is 5. 
*e=&'f';  // what is pointed to by e (which is a char * itself, and is still d!) 
       // is set to the address of the memory location holding the value 'f'. 
       // does not change c or e, just d! 

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

+0

Что вы делаете, когда видите это в объявлении функции? – jkeys

+0

Я бы предложил расширить способ чтения * в объявлениях, так что 'int * p' читает как« то, на что указывает 'p' - это' int' ', а не '' p' является 'int * '', которая немного туманна. – caf

1

Я думаю, что вы спутать:

char a[8]; 
char *p=a; 

, который является законным и делает то же самое, как:

char a[8]; 
char *p=NULL; 
p=a; 

с:

char a[8]; 
char *p=NULL; 
*p=a; 

, который, как другие говорили, будет генерировать компиляции ошибки или ошибки сегментации.

In the left side of declarations you should read *x as pointer(x) while in 
statements it must be read as value_pointed_by(x). &x on the other hand 
would be pointer_to(x) 
+0

Я обычно читаю объявление 'char * p', поскольку« * p является символом », а не« p является символом char », который в ранние годы помогал держать вещи прямо (а также помогает в чтении более сложных заявлений) , В ретроспективе, вероятно, было бы яснее, если бы синтаксис был '& char p', чтобы объявить p указателем на char. – caf

+0

Да, было бы лучше, если бы его рассматривали как другой тип. Однако, C как бы то ни было, лучше объявить char * p, а не char * p, поскольку первая не будет применяться к последующим переменным, что делает его нелогичным. char * p, q; char * p; char q; вместо char * p, * q; и это то, во что вы могли бы верить. – jbcreix

Смежные вопросы