Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Указатель на массив, как на строку, В С, без переменной, возможно? 
:(
    Опции темы
0xDEAD
Дата 21.10.2011, 13:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Добрый день!

В С можно делать так:

Код

#define ARR_SIZE 3

char *array[ARR_SIZE] = {
    "\x05\x02\x37", 
    "", 
    "\x09"
};

void main()
{
    int i;
    char *p;

    for(i=0; i<ARR_SIZE; i++)
    {
        printf("item number %d:\n", i);
        for(p = array[i]; *p != '\0'; p++)
            printf("\tsubitem: %hhd\n", *p);
    }
}


Результат:
Цитата
item number 0:
        subitem: 5
        subitem: 2
        subitem: 55
item number 1:
item number 2:
        subitem: 9


Это весьма удобно, указатель на массив без лишних переменных.
Вопрос: можно ли в С сделать так с int?

Что-то вроде:
Код

int *array[ARR_SIZE] = {
    {1, 2, 3}, 
    {}, 
    {9}
};


Спасибо!
PM MAIL   Вверх
bsa
Дата 21.10.2011, 14:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



нельзя
PM   Вверх
math64
Дата 21.10.2011, 14:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



Именно так написать нельзя, но можно написать эквивалентный код:
Код

#include <stdio.h>

static int array1[] = {1, 2, 3};
static int array2[0];
static int array3[] = {9};
int *array[] = {
  array1,
  array2,
  array3
};
#define ARR_SIZE(array) (sizeof(array)/sizeof(array[0]))
int sizes[] = { ARR_SIZE(array1), ARR_SIZE(array2), ARR_SIZE(array3) };
int main() {
  int i, j;
  for(i = 0; i < ARR_SIZE(array); i++) {
    for(j = 0; j < sizes[i]; j++)
      printf("%d ", array[i][j]);
    printf("\n");
  }
}

PM   Вверх
0xDEAD
Дата 21.10.2011, 15:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Нашел такой документ:
Anonymous Arrays in C

Там написано, что в С можно сделать вот так:

Код

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


Но что-то оно у меня в VS не работает.
PM MAIL   Вверх
math64
Дата 21.10.2011, 20:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



gcc компилирует, но нужны дополнительные скобки:
Код

#include <stdio.h>
#define ARR_SIZE(array) (sizeof(array)/sizeof(array[0]))
#define SIZE_ARR(array) { ARR_SIZE(array), array }
struct size_int_array {int size; int * arr; } array[] = {
  SIZE_ARR( ( (int[]) { 1, 2, 3} )  ),
  SIZE_ARR( ( (int[]) {} )  ),
  SIZE_ARR( ( (int[]) {9} )  )
};

int main() {
  int i, j;
  for(i = 0; i < ARR_SIZE(array); i++) {
    for(j = 0; j < array[i].size; j++)
      printf("%d ", array[i].arr[j]);
    printf("\n");
  }
}

Особенно интересно, что можно почситать размер анонимного массива без генерации кода самого массива.
Вот сгенерированный ассемблерный код (без кода main):
Код

.globl _array
    .data
    .align 4
_array:
    .long    3
    .long    ___compound_literal.2
    .long    0
    .long    ___compound_literal.5
    .long    1
    .long    ___compound_literal.8

    .data
    .align 4
___compound_literal.2:
    .long    1
    .long    2
    .long    3
.lcomm ___compound_literal.5,16
    .align 4
___compound_literal.8:
    .long    9

PM   Вверх
0xDEAD
Дата 21.10.2011, 20:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Как раз то, что мне нужно, жалко в MSVC такого нету.

Мне нужно сделать массив с информацией, которую в будущем было бы удобно изменить.
Наверно придется сделать со всякими array1, array2...
PM MAIL   Вверх
math64
Дата 21.10.2011, 20:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



Но! Только C, не С++ - в VS C это C++ без классов и новые возможности C, не включённые в C++ отсутствуют.
PM   Вверх
math64
Дата 21.10.2011, 21:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



можно генерировать макросами, вот самое простое, что у меня получилось:
Код

#include <stdio.h>
#define ARR_SIZE(array) (sizeof(array)/sizeof(array[0]))
#define SIZE_ARR(array) { ARR_SIZE(array), array }
#define ARRAY_DEF1(name, n, values) name##n[] = values;
#define ARRAY_SIZE_NAME1(name, n, values) SIZE_ARR(name##n)
#define C ,
#define ARRAY_DEFS(type, name, values) values(type name, ARRAY_DEF1, )
#define ARRAY_DEF(type, name, values) type name[] = { values(name, ARRAY_SIZE_NAME1, C) };
//#define V(...) { __VA_ARGS__ }

struct size_int_array {int size; int * arr; };
#define VALUES(N, A, D) \
  A(N, 1, {1 C 2 C 3} ) D \
  A(N, 2, {} ) D \
  A(N, 3, {9} )

ARRAY_DEFS(int, array, VALUES)
ARRAY_DEF(struct size_int_array, array, VALUES)

int main() {
  int i, j;
  for(i = 0; i < ARR_SIZE(array); i++) {
    for(j = 0; j < array[i].size; j++)
      printf("%d ", array[i].arr[j]);
    printf("\n");
  }
}

Не очень наглядно -
например, для передачи в макрос значений массива приходится использовать макрос C вместо запятой или макрос с переменным числом аргументов, который тоже не все компиляторы поддерживают (последняя VS вроде поддерживает).
PM   Вверх
0xDEAD
Дата 21.10.2011, 22:05 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



VC ругается на пустой элемент, {}, что не очень критично, а так работает.
Щас буду изучать, я сам тоже что-то такое сделать пытался, но не получилось.
PM MAIL   Вверх
math64
Дата 21.10.2011, 23:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



у gcc есть ключ -E - выполнять только препроцессирование, без компиляции. У VS должен быть такой же. Без него разобраться в подобных макросах сложно. Перед запуском с этим ключом лучше закомментировать #include <stdio.h>, чтобы не мешался.
PM   Вверх
0xDEAD
Дата 21.10.2011, 23:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Упростил до такого вида:

Код
#include <stdio.h>

#define ARRAYS_DEF(l, ...)  static int array_temp_ ## l [] = { __VA_ARGS__ };
#define ARRAYS_LIST(l, ...) array_temp_ ## l ,

#define VALUES(A)              A(1,\
    1, 2, 3,                -1)A(2,\
    1,                      -1)A(3,\
    9,                      -1)A(4,-1)

VALUES(ARRAYS_DEF)
int *array[] = { VALUES(ARRAYS_LIST) };

int main()
{
    int i, j;

    for(i = 0; array[i][0] != -1; i++)
    {
        for(j = 0; array[i][j] != -1; j++)
            printf("%d ", array[i][j]);

        printf("\n");
    }
}


Еще у VC есть штука, которая называется __COUNTER__, но у меня не получилось придумать, куда ее сюда всунуть чтоб убрать номера 1, 2, 3, 4
PM MAIL   Вверх
math64
Дата 22.10.2011, 00:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



__COUNTER__ можно использовать только разбив исходник на отдельные файлы:
Код

//array.h
extern int* array[];
//array_values.h
#include "array.h"
#define ARRAYS_DEF(...)  int array_temp_ ## __COUNTER__ [] = { __VA_ARGS__ };
#define ARRAYS_LIST(...) array_temp_ ## __COUNTER__ ,
#define VALUES(A) \
A(1, 2, 3, -1) \
A(1, -1) \
A(9, -1) \
A(-1)
//array_def.c
#include "array_values.h"
VALUES(ARRAYS_DEF)
//array_list.c
#include "array_values.h"
int *array[] = { VALUES(ARRAYS_LIST) };
//main.c
#include "array.h"
int main() { ... }

Кстати, последняя запятая в инициализации массива не мешается? Понятно, что ошибок компиляции нет, но не увеличивается ли размер массива на 1?

PM   Вверх
0xDEAD
Дата 22.10.2011, 00:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Не, это уже слишком smile

Цитата(math64 @  22.10.2011,  00:04 Найти цитируемый пост)
не увеличивается ли размер массива на 1?

Неа.
PM MAIL   Вверх
math64
Дата 22.10.2011, 08:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



Предложенный мною в предыдущем посте вариант не работает - нужно генерировать ещё extern int array1[];
Но есть другой вариант - вместо массива генерировать switch, удобнее использовать, контроль неправильного индекса в default,
вместо __COUNTER__ использую __LINE__, которая есть везде:
Код

#include <stdio.h>
#define ARR_SIZE(array) (sizeof(array)/sizeof(array[0]))
#define SIZE_ARR(array) { ARR_SIZE(array), array }
#define SWITCH(index) \
  /* printf("switch: %d\n", index + __LINE__ + 1); */ \
  switch(index + __LINE__ + 1) {
#define CASE(...) case __LINE__: \
{ static int array[] = { __VA_ARGS__ }; \
  /* printf ("case: %d\n", __LINE__); */ \
  size = ARR_SIZE(array); parray = array; \
  break; }
#define DEFAULT default: \
{ static int array[0]; size = -1; parray = array; break; }
#define ENDSWITCH }
int* getArray(int index, int* psize) {
int size, *parray;
SWITCH(index)
  CASE(1,2,3)
  CASE()
  CASE(9)
  DEFAULT
ENDSWITCH
if (psize) *psize = size;
return parray;
}

int main() {
  int i, j, size, *parray;
  for(i = 0; ; i++) {
    parray = getArray(i, &size);
    if (size < 0) break;
    for(j = 0; j < size; j++)
      printf("%d ", parray[j]);
    printf("\n");
  }
}


Добавлено @ 08:20
Раз VS ругается на {}, нужно добавить ещё макрос
Код

#define CASE_EMPTY case __LINE__: \
{ static int array[0] \
  size = 0; parray = array; \
  break; }


Это сообщение отредактировал(а) math64 - 22.10.2011, 08:21
PM   Вверх
0xDEAD
Дата 22.10.2011, 18:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 77
Регистрация: 20.9.2009

Репутация: нет
Всего: 3



Спасибо за советы, вот к чему я пришел:

Код
#include <stdio.h>

#define RET_ARRAY(t, ...) {static t temp_array__[] = {__VA_ARGS__}; return temp_array__;}

int *get_array(int a)
{
    switch(a)
    {
    case 0: RET_ARRAY(int, 1, 2, 3, -1);
    case 1: RET_ARRAY(int, -1);
    case 2: RET_ARRAY(int, 9, -1);
    }

    return NULL;
}

int main()
{
    int i, j, *parray;

    for(i = 0; parray = get_array(i); i++)
    {
        for(j = 0; parray[j] != -1; j++)
            printf("%d ", parray[j]);

        printf("\n");
    }

    return 0;
}


Не так красиво как с точки зрения исходника, так и с точки зрения результата:
Код

/MOV EAX,DWORD PTR [EBP-4]
|SUB EAX,0                                            ;  Switch (cases 0..2)
|JE SHORT test.00391030                  ; ПРОВЕРКА!
|DEC EAX
|JE SHORT test.00391029                  ; ПРОВЕРКА!
|DEC EAX
|JNZ SHORT test.00391064                 ; ПРОВЕРКА!
|MOV EDI,test.0039302C                                ;  Case 2 of switch 00391017
|JMP SHORT test.00391035
|MOV EDI,OFFSET test.array_temp_2                     ;  Case 1 of switch 00391017
|JMP SHORT test.00391035
|MOV EDI,OFFSET test.array_temp_1                     ;  Case 0 of switch 00391017

; печатаем

|INC DWORD PTR [EBP-4]
\JMP SHORT test.00391014


6 лишних проверок и еще пару команд.
Правда при большом switch-case компилятор наверно создаст таблицу...

Но все же лучше чем предыдущие варианты.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.2282 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.