2015-05-29 6 views
4

Почему я не могу определить массивC - массив символов и сажу указатель

char **pp={ "123", "456", "789" }; 

Но я могу определить его как символ * [], и отправить его в функцию, которая будет принимать его в качестве символ **

char *pp[]={ "123", "456", "789" }; 
fun(pp); 

void fun(char **pointerToPointer) 
{ 
    //++(**pointerToPointer);//error 
    printf("%s", *pointerToPointer); 
} 
//output::"123" 

И почему я не могу увеличиваем

++(**pointerToPointer); 
+0

я могу определить 'символ * * pp = {"123", "456", "789"}; '.. О ком компилятор мы говорим? –

+0

Какова цель использования '++ (** pointerToPointer)'? – Subinoy

+1

@EugeneSh. , С предупреждениями, хотя ... –

ответ

1

Вот char *pp[]={ "123", "456", "789" }; правильно, потому что:

  • Здесь представлен массив указателей, который может быть использован для указания массива элементов данных с каждым элементом массива указателей, указывающим на элемент массива данных.
  • Поскольку мы назначаем каждый массив указателю , он отлично работает.

Но в случае char **pp={ "123", "456", "789" };

  • Здесь инициализация памяти не происходит.
  • Вместо этой первой строки назначается указатель, а затем компилятор генерирует предупреждение, указывающее, что другие многие значения отбрасываются.

Как CoolGuy сказал ++(**pointerToPointer) это ошибка, потому что доступ к 1 из "123" строки, и пытается изменить значение 1 к 2, и так как они являются строковые литералы, присваивающих не может быть сделано. Вы можете видеть только значение приращения печати: printf("%c\n", **pointerToPointer+1); , которая даст выход: 2

Вы можете решить с помощью раствора, предоставленной CoolGuy в comment-

  1. Изменяя char *pp[]={ "123", "456", "789" }; в char pp[][100]={ "123", "456", "789" };
  2. изменяя void fun(char **pointerToPointer) к void fun(char (*pointerToPointer)[100])

Это правильно, потому что здесь изменяется значение **pointerToPointer.

Это причины для меня. А для предупреждения:

warning: excess elements in scalar initializer [enabled by default]

вы можете увидеть ссылку в here, которая является наилучшим объяснением его мне.

+0

один массив означает? @CoolGuy Пожалуйста, отредактируйте его, если вы видите ошибки – Subinoy

+0

'char * pp [] = {" 123 "," 456 "," 789 "};' объявляет массив указателей, каждый из которых имеет тип 'char *'. На самом деле здесь можно увидеть 4 массива (я ошибался), каждый строковый литерал также является массивом. –

+0

Да, это из-за меня, я его отредактировал. Я просто забыл о концепции. Извините за ошибки @CoolGuy – Subinoy

2

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

int *ptr = { 1, 2, 3 }; 

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

ptr - один объект, поэтому может быть выполнено не более одного инициализатора, и ожидаемая форма этого инициализатора является указателем (который не является 1).

В самом деле этот код явно незаконным в соответствии с C11 6.7.9/11:

Инициализатор скаляр должно быть одно выражение, необязательно заключены в скобки

Однако существует gcc bug/feature, где он допускает избыточные инициализаторы для скаляра и игнорирует их. Кроме того, некоторые компиляторы могут «быть полезными» и «только» выдавать предупреждение и инициализировать ptr, чтобы указать на адрес 1, где бы это ни было.

«скаляр» означает объект, который не является структурой или массивом.


Так как C99 вы можете написать:

int *ptr = (int []){1, 2, 3}; 

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

Этот массив изменен; для неперемещаемого используйте вместо него int const *ptr = (int const[]){1, 2, 3};.


Замена int на char *, мы видим, что вы могли бы написать:

char **p = (char *[]){ "123", "456", "789" }; 

в этом случае указатели в массиве изменчивы, но то, что они указывают на (то есть строковые литералы) все еще нет.

Обратите внимание, что при работе со строковыми литералами вы всегда должны использовать char const *, потому что они не изменяемы. Тот факт, что строковые литералы имеют тип char [N] исторический пережиток, прежде чем const был добавлен в С. Итак:

char const **pp = (char const *[]){ "123", "456", "789" }; 

или с не изменяемых указателей на строки:

char const *const *pp = (char const *const []){ "123", "456", "789" }; 
Смежные вопросы