Указатели и массивы в C, требуется больше понимания

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

char *name = "Madonah";
int i= 0;
for (i=0;i<7; i++){
    printf("%c", *(name+i));
}

char name1 [7] = "Madonah";
printf("\n");
int j= 0;
for (j=0;j<7; j++){
    printf("%c", name1[j]);
}

char *name2 = "Madonah";
printf("\n");
int k= 0;
for (k=0;k<7; k++){
    printf("%c", name2[k]);
}

char name3 [7] = "Madonah";
printf("\n");
int m= 0;
for (m=0;m<7; m++){
    printf("%c", *(name+m));
}

Результаты:

Madonah
Madonah
Madonah
Madonah

Ответы

Ответ 1

Верно, что указатели и массивы эквивалент в некотором контексте, "эквивалент" означает, что они не идентичны и даже не взаимозаменяемы. Массивы не являются указателями.
Это арифметика указателей и индексирование массива, эквивалентные, указатели и массивы отличаются.

какой из них предпочтительнее и преимущества/недостатки?

Это зависит от того, как вы хотите их использовать. Если вы не хотите изменять строку, вы можете использовать

char *name = "Madonah";  

В основном это эквивалентно

char const *name = "Madonah";  

*(name + i) и name[i] оба одинаковы. Я предпочитаю name[i] над *(name + i), поскольку он опрятен и используется наиболее часто программистами на C и С++.

Если вам нравится изменять строку, вы можете пойти с

char name1[] = "Madonah";

Ответ 2

В C, a[b], b[a], *(a+b) эквивалентны, и нет никакой разницы между ними 3. Таким образом, у вас есть только 2 случая:

char *name = "Madonah"; /* case 1 */

и

char name3 [7] = "Madonah"; /* case 2 */

Первый - это указатель, который указывает на строковый литерал. Последний представляет собой массив из 7 символов.

который является предпочтительным, зависит от вашего использования name3.

Если вы не намерены модифицировать строку, то вы можете использовать (1), и я также сделаю ее const char*, чтобы она понятна и гарантировала, что строковый литерал не будет изменен случайно. Изменение строкового литерала undefined поведение в C

Если вам нужно его изменить, тогда (2) следует использовать как массив символов, которые вы можете изменить. Следует отметить, что в случае (2) вы явно указали размер массива как 7. Это означает, что массив символов name3 не имеет нулевого терминатора (\0) в конце. Поэтому он не может использоваться как строка. Я бы предпочел не указывать размер массива и позволить компилятору вычислить его:

char name3 [] = "Madonah"; /* case 2 */
/* an array of 8 characters */

Ответ 3

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

char a[] = "hello";
char *p = "world";

Что происходит в первом случае, достаточное количество памяти выделяется для a (6 символов) в стеке, а строка "hello" копируется в память, которая начинается с a. Следовательно, вы можете изменить эту область памяти.

Во втором случае "мир" выделяется где-то еще (обычно в области только для чтения), и возвращается указатель на эту память, который просто хранится в p. Вы не можете изменить строковый литерал в этом случае через p.

Вот как это выглядит:

enter image description here

Но для вашего вопроса придерживайтесь обозначения, которое проще, я предпочитаю []. Дополнительная информация о связи между массивами и указателями здесь.

Ответ 4

Во всех случаях в C pointer + index совпадает с pointer[index]. Кроме того, в C имя массива, используемое в выражении, рассматривается как указатель на первый элемент массива. Вещи становятся немного более мистифицированными, если вы считаете, что добавление является коммутативным, что делает также index + pointer и index[pointer] законным. Компиляторы обычно генерируют аналогичный код независимо от того, как вы его пишете.

Это позволяет использовать такие классные вещи, как "hello"[2] == 'l' и 2["hello"] == 'l'.

Ответ 5

удобно использовать синтаксис массива для произвольного доступа

int getvalue(int *a, size_t x){return a[x];}

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

void copy_string(char *dest, const char *src){while((*dest++=*src++));}

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

Ответ 6

Для практического использования идиом указателя и массива в C все это действительные кодовые блоки и иллюстрирующие разные способы выражения одной и той же вещи.

Для производственного кода вы не использовали бы ни один из них; вы бы использовали что-то более простое для людей, чтобы читать и, скорее всего, оптимизироваться компилятором. Вы обойдетесь без петли и просто скажете:

printf("%s", name);

(Обратите внимание, что для этого требуется name включить символ \0 в конце строки, на который полагается printf. Определения name1 и name3, как написано, не выделяют необходимые 8 байт.)

Если вы пытались сделать что-то сложное в своем коде, которое требовало одного из более подробных методов, которые вы опубликовали, то какой метод вы выбрали, будет зависеть именно от того, какую сложную вещь вы пытались сделать (что вы, конечно, объясните в коде комментарии - в противном случае вы могли бы взглянуть на свой собственный код через шесть месяцев и спросить себя: "Что, черт возьми, я тут делаю?" ). В общем, для выщипывания символов из строки name[i] является более распространенной идиомой, чем *(name+i).

Ответ 7

  • char name[] = "Madonah";
  • char* name = "Madonah";

При объявлении внутри функции первый параметр дает дополнительные операции при каждом вызове функции. Это связано с тем, что содержимое строки копируется из секции данных RO в стек каждый раз, когда вызывается функция.

Во втором варианте компилятор просто устанавливает переменную, указывающую на адрес этой строки в памяти, которая является постоянной во время выполнения программы.

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

Обратите внимание, что все приведенные выше детали зависят от реализации компилятора и не продиктованы стандартом языка C.

Ответ 8

Могу ли я узнать, какой из них прост в использовании [...]

Попробуйте использовать оператор индексирования [].

Один раз ваш код становится более сложным, и вы заметите, что вещи "легче" кодировать, используя арифметические выражения указателя.

Это обычно будет, когда вы также начинаете использовать адрес-оператора: &.

Если, например, вы видите свое "я" в необходимости кода:

char s[] = "Modonah";
char * p = &s[2]; /* This gives you the address of the 'd'. */

вы скоро заметите, что это "проще" написать:

char * p = s + 2; /* This is the same as char * p = &s[2];. */

Ответ 9

Массив - это просто переменная, содержащая несколько значений, каждое значение имеет индекс, возможно, вы уже знаете это. Указатели - одна из тех вещей, о которых вам не нужно знать, пока вы не осознаете, что вам нужно их использовать. Указатели не являются самими переменными, они буквально указывают на переменные.
Пример того, как и почему вы можете использовать указатель.
Вы создаете переменную в одной функции, которую вы хотите использовать в другой функции.
Вы можете передать переменную в новую функцию в заголовке функции. Это эффективно КОПИРОВАНО значения из исходной переменной в новую переменную, локальную для новой функции. Изменения, внесенные в новую функцию, изменяют только новую переменную в новой функции.
Но что, если вы хотите, чтобы изменения, внесенные в новую функцию, изменили исходную переменную, где она находится в первой функции?
Вы используете указатель.
Вместо передачи фактической переменной в новую функцию вы передаете указатель на переменную. Теперь изменения, внесенные в переменную новой функции, отражаются в исходной переменной в первой функции.
Вот почему в вашем собственном примере, используя указатель на массив и используя фактический массив, в то же время функция имеет одинаковые результаты. Оба они говорят "изменить этот массив".