Инициализация массива указателей на указатели - PullRequest
4 голосов
/ 04 марта 2009

Этот пример отлично работает:

static char *daytab[] = {
    "hello",
    "world"
};

Это не:

static char *daytab[] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

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

Может ли кто-нибудь объяснить мне, почему второй пример не так?

P.S. Возможно, вы могли бы написать это так (еще не проверял):

static char a[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char b[] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
static char *daytab[] = {
    a,
    b
};

Но это выглядит слишком много работы:).

Ответы [ 6 ]

3 голосов
/ 10 декабря 2009

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

#include <iostream>
using namespace std;

int *a[] = {
  (int[]) { 0 } ,
  (int[]) { 1 , 2 } ,
  (int[]) { 3 , 4 , 5 } ,
  (int[]) { 6 , 7 , 8 , 9 }
};

main()
{
  cout
  << a[0][0] << endl
  << a[1][0] << " " << a[1][1] << endl
  << a[2][0] << " " << a[2][1] << " " << a[2][2] << endl
  << a[3][0] << " " << a[3][1] << " " << a[3][2] << " " << a[3][3] << endl;
}

И я получаю вывод, компилируя с gnu g ++

0
1 2
3 4 5
6 7 8 9

и компиляция с Intel ICPC

0
1 1
40896 32767 -961756724
0 32767 4198878 0

Таким образом, синтаксис в принципе выглядит правильным, просто компилятор Intel не поддерживает его корректно, вероятно, из-за отсутствия общего использования этого стиля.


--- редактировать ---

Вот также версия C (как требуется):

#include <stdio.h>

int *a[] = { 
  (int[]) { 0 } , 
  (int[]) { 1 , 2 } , 
  (int[]) { 3 , 4 , 5 } , 
  (int[]) { 6 , 7 , 8 , 9 } 
};

int main()
{
  printf( "%d\n" , a[0][0] );
  printf( "%d %d\n" , a[1][0] , a[1][1] );
  printf( "%d %d %d\n" , a[2][0] , a[2][1] , a[2][2] );
  printf( "%d %d %d %d\n" , a[3][0] , a[3][1] , a[3][2] , a[3][3] );
}

Я проверил его с помощью gcc и clang, и он выводит правильный результат. Btw. неправильный вывод компилятора intel был ошибкой компилятора.

3 голосов
/ 04 марта 2009

Это:

{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}

Это просто инициализатор массива. Сам по себе он не создает массив. В первом примере, когда вы присвоили строковый литерал указателю, DID создал эти строки в статическом хранилище (скрытом для вас), а затем просто назначил им указатели.

Так что, по сути, нет способа инициализировать ваш символ * с помощью инициализатора массива. Вам необходимо создать реальный массив и присвоить ему эти числа. Вы должны сделать что-то вроде:

char a[][] = { {32, 30, 0}, {34, 32, 33, 0} }; // illegal

Но это незаконно.

Вам нужно построить массив отдельно и назначить их в массив, как в вашем последнем примере.

3 голосов
/ 04 марта 2009

Попробуйте:

static char daytab[][13] = {
    {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
    {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

Это не символы *. Они тоже не полукоксы. Вы, вероятно, хотите:

static int daytab[][13] ...
1 голос
/ 07 февраля 2012
static char **daytab;
daytab=(char**)malloc(2*sizeof(char*));
daytab[0]=(char*)(char[]){0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
daytab[1]=(char*)(char[]){0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
0 голосов
/ 04 марта 2009

Обратите внимание, что ваш первый пример тоже не работает. Это должно быть:

static const char *daytab[] = {
    "hello",
    "world"
};

Обратите внимание на const .

Редактировать: И под "не работает" я имею в виду плохую практику и склонность к ошибкам, что, возможно, еще хуже.

0 голосов
/ 04 марта 2009

Синтаксис вашего второго примера - это синтаксис литерала многомерного массива.

Многомерный массив не является массивом указателей на массивы.

Было бы удивительно, если бы синтаксис для одной вещи был также синтаксисом для другой вещи, в зависимости от типа, который объявлен.

В первом примере, поскольку строковый литерал вычисляется по указателю, а не по значению массива, значение оценивается как массив указателей. Поскольку литерал массива оценивается как значение массива, а не как указатель, второй пример - многомерный массив - массив, элементы которого являются значениями массива, а не массив, элементы которого являются указателями на значения массива.

Следующий код демонстрирует комбинации многомерных массивов, указателей на массивы, массивов указателей и указателей на указатели. Из этих трех только массивы указателей и указателей на указатели совместимы друг с другом:

void multi_array (int x[][4], size_t len) // multidimensional array
{
    for (size_t i = 0; i < len; ++i)
        for (size_t j = 0; j < 4; ++j)
            putchar( 'a' + x[i][j] );
    putchar('\n');
}

void ptr_array (int (*x)[4], size_t len) // pointer to an array
{ ... as multi_array  }

void array_ptr (int *x[], size_t len) // array of pointers
{ ... as multi_array  }

void ptr_ptr (int **x, size_t len) // pointer to pointer
{ ... as multi_array  }

int main() {
    int a[][4] = { { 1,2,3,4 } };
    int b[] = { 1,2,3,4 };
    int* c[] = { b };

    multi_array( a, 1 );
    multi_array( (int[][4]) { { 1,2,3,4} }, 1 ); // literal syntax as value
    ptr_array( &b, 1 );
    array_ptr( c, 1 );
    ptr_ptr( c, 1 ); // only last two are the same

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...