Итерация указателя против массива символов - PullRequest
1 голос
/ 01 октября 2019

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

char string[] = "Hi";
char * pstring = string;
while(*pstring)
    printf("%c", *pstring++);

Но если я уберу указатель, он не будет:

char string[] = "Hi";
while(*string)
    printf("%c", *string++);

Почему работает первый? В чем основное различие между итерацией по указателю и массиву?

Ответы [ 2 ]

1 голос
/ 01 октября 2019

На самом деле довольно много причин, почему второй не работает. Я уверен, что вы это знаете, но я просто повторю: массив не является указателем. Массивы конвертируются только в указатели. Это происходит автоматически, и это происходит «очень часто», но массивы и указатели по-прежнему являются разными типами. С точки зрения языка, вы просто не можете присвоить массиву (значения l типа массива не являются «изменяемыми значениями l»), и, в частности, «скрытое» присваивание string = string + 1 в string++ не работает. Вы можете, конечно, назначить переменную указателя. По этой причине в стандарте C ++ определено для работы только с числовыми («действительными») и указательными типами, а это означает, что вам нельзя указывать массив.

В терминахиз почему правила таковы, один ход мыслей начинается с того, что он замечает, что тип массива является «полным» только тогда, когда он имеет размер, т.е. если у вас есть переменная типа массива, его размерчасть своего типа. Попытка изменить string с помощью арифметики, как вы делаете здесь, потребует изменения типа string, потому что размер изменится, но это не разрешено в C. (Обратите внимание, что char string[]; является недопустимым объявлением, потому что ононе указывает размер; когда вы добавили инициализатор, вы сказали C выводить из него размер (3).) В версии указателя pstring - это char*, как и pstring + 1, поэтомунет проблем. В версии массива вы должны иметь char string[3] перед циклом и char string[1] после. Хуже того, окончательный размер string будет зависеть от данных в нем, поэтому невозможно будет предсказать его с точки зрения языка. Лучше не открывать, что может червей, не так ли?

Идея увеличения string также не работает, потому что в C "объект массива" на 1021 * больше , чем "связка смежных"элементы». Когда вы объявляете string, да, вы создаете кучу char объектов, которые являются смежными в памяти, но вы также «благословляете» (это не технический термин, если вы не используете Perl :)) эту память вбудучи char[3] объектом. Вероятно, с точки зрения реальной машины это «благословение» на самом деле ничего не значит и не означает, но с точки зрения абстрактной машины, на которой работают программы на Си, есть разница. В частности, нет ни объекта char[2], расположенного по адресу памяти string + 1, ни char[1] в string + 2. Таким образом, если бы вы увеличили string, , не было бы массива для string, на который можно было бы ссылаться больше.

Я полагаю, вы можете свести все это к интуиции, что массивна самом деле просто "куча переменных". То есть, когда вы объявили char string[3];, должно появиться ощущение, что вы char string_0, string_1, string_2;. Это как если бы у вас было struct { int x; char y; } test; - это похоже на запись int test_x; char test_y;. «Увеличение группы переменных» совершенно бессмысленно, поэтому, конечно, string++ и test++ запрещены. С string у вас есть возможность создать char *pstring, такой, что pstring = &string_0, pstring + 1 = &string_1, pstring + 2 = &string_2, но это не меняет того факта, что выполнение арифметики на самом string (особенно деструктивно увеличивающемся)это) не имеет смысла.

0 голосов
/ 01 октября 2019

Вот мои два бита ....

Почему работает первый?

Указатель "pstring" является переменной. Это означает, что указателю «pstring» может быть присвоено новое значение.

pstring ++ - это «pstring = pstring + 1» (разрешено).

Другие допустимые операции с указателями:

  • Присвоение указателей одного типа.
  • Сложение или вычитание указателя и целого числа.
  • Вычитание или сравнение двух указателей на элементы одного и того же массива.
  • Назначение или сравнение указателя с нулем (NULL).

В чем основное различие между итерацией через указатель и массив?

Имямассива (синоним местоположения первого элемента) , а не «переменная» и всегда будет ссылаться на одно и то же хранилище. Хотя целое число может быть добавлено или вычтено из имени массива, переназначение нового значения имени массива недопустимо.

string ++ - это "string = string + 1" (не разрешено).

Разница в кодировании дополнительно экстраполируется следующим образом:

char string[] = "Hi";
int i = 0;
while(*(string+i)){ // or string[i]
  printf("%c", *(string+i));// or string[i]
  i++;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...