Передача указателя в массив массивов через функцию - PullRequest
2 голосов
/ 02 января 2009

В коде есть указатель на массив массивов, т. Е. Список имен. Я хочу, чтобы содержимое каждого из массивов в указателе (NameList) печаталось по одному. Приведенный ниже код не может выполнить задачу. Pls. помощь.

int Data1[] = {10,10};
int Data2[] = {20,20};
int Data3[] = {30,30};

int *NameList[] = {Data1, Data2, Data3};
main()
{  Function(NameList); }

Function(int *ArrayPointer)
  {
    int i, j, index=0;
    for (i=0; i < 3; i++)
      {
        for (j=0; j < 2; j++)
          {
             //It does not print the data
             printf("\nName: %s",  ArrayPointer[index++]);
          } 
        index=0;         //Counter reset to 0
        ArrayPointer++;  //Pointer is incremented by one to pick next array in the pointer
      }
  }
print("code sample");

Еще одна заметка из оригинального постера вопроса:

Я закончил игру pacman в Turbo C. Я полировал некоторые графические процедуры, чтобы их можно было легко использовать повторно. Это только небольшой образец, созданный с целью помочь и понять концепцию. Все данные в коде на самом деле являются массивами символов для спрайтов. Теперь я просто хочу вызвать функцию, передающую указатель, чтобы каждый массив указателя выводился на экран. Как этот код может быть изменен, чтобы справиться с этим? Я на самом деле застрял здесь.

Ответы [ 6 ]

5 голосов
/ 02 января 2009

Черт возьми лит , еще раз ты избил меня до удара за считанные минуты. (Если бы у меня не было детей, которые продолжают просыпаться ...)

Ааа, какого черта. Возможно, это еще кому-нибудь пригодится.


О, и просто прибить эту вещь:

  • Массивы, такие как int и [4] , выделяют пространство памяти для своих данных.
  • Указатели, такие как int * p , выделяют только целое пространство памяти для указателя на другое место в памяти.
  • Именно поэтому мы можем использовать sizeof для массивов и получить полный объем памяти, но не для указателей.

Кроме этого небольшого различия, между int [] и int * действительно нет большой разницы. (Рассмотрим, сколько людей объявляют * main (int argc, char ** argv) против main (int argc, char * argv []) .)


ВНИМАНИЕ: Все адреса памяти здесь вымышленные. Я просто делаю их, чтобы проиллюстрировать точку.

Дано:

int Data1[] = {10,11};
int Data2[] = {20,22};
int Data3[] = {30,33};

Теперь у нас есть 3 блока памяти. Скажи:

0xffff0000-0xffff0003  with a value of (int)(10)
0xffff0004-0xffff0007  with a value of (int)(11)

0xffff0008-0xffff000b  with a value of (int)(20)
0xffff000c-0xffff000f  with a value of (int)(22)

0xffff0010-0xffff0013  with a value of (int)(30)
0xffff0014-0xffff0017  with a value of (int)(33)

Где:

Data1 == & Data1 [0] == 0xffff0000
Data2 == & Data2 [0] == 0xffff0008
Data3 == & Data3 [0] == 0xffff0010

НЕТ , я не собираюсь перейти к порядку байтов с прямым порядком байтов против байтов с прямым порядком байтов здесь!

Да, в этом случае Data1 [2] == Data2 [0]. Но вы не можете полагаться на то, что ваш компилятор размещает вещи в памяти так же, как я их выложил здесь.

Далее:

int *NameList[] = {Data1, Data2, Data3};

Итак, теперь у нас есть еще один блок памяти. Скажи:

0xffff0018-0xffff001b  with a value of (int*)(0xffff0000)
0xffff001c-0xffff001f  with a value of (int*)(0xffff0008)
0xffff0020-0xffff0023  with a value of (int*)(0xffff0010)

Где:

NameList == & NameList [0] == 0xffff0018

Обратите внимание, что NameList имеет тип int ** и NOT int * type!

Затем мы можем написать:

void Function(int **ArrayPointer)
{
  for ( int i=0; i < 3;  i++ )
    for ( int j=0; j < 2; j++)
      printf("Name: %d\n",  ArrayPointer[i][j] );
}

int main() {  Function(NameList); }

ArrayPointer преобразуется в (int **) 0xffff0018.

ArrayPointer [0] == * ((int **) 0xffff0018) == (int *) (0xffff0000) == Data1.

ArrayPointer [0] [1] == * ((* (int **) 0xffff0018) + 1) == (int) * ((int *) 0xffff0000 + 1) == (int) * (int * ) 0xffff0004 == Данные1 [1].


Вы можете просмотреть арифметику указателей: array [N] == * (array + N)

3 голосов
/ 02 января 2009

main должен возвращать тип. Вы забыли поставить «int» в качестве возвращаемого типа (неявный int в C ++ запрещен).

Сказав это, я не уверен, что вы подразумеваете под

// It does not print the data
printf("\nName: %s",  ArrayPointer[index++]);

ArrayPointer[index++] будет, как определено в списке параметров, вернуть int. Как это должно хранить имя ? Он будет хранить целое число !

Еще раз сказано, что вы не можете вызывать эту функцию (каламбур) с этим конкретным аргументом. Давайте рассмотрим ваши типы:

int Data1[] = {10,10};
int Data2[] = {20,20};
int Data3[] = {30,30};

int *NameList[] = {Data1, Data2, Data3};

Data1      Data2      Data3      NameList
int[2]     int[2]     int[2]     int*[3]

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

int (*NameList)[N][M] = Some3DimensionalArray;

Это не имеет смысла вообще. Так что у тебя есть?

Data1 = array of 2 int
Data2 = array of 2 int
Data3 = array of 2 int
NameList = array of poiners to int

Это - это то, что вы получили. И вы передаете NameList в функцию, которая хочет указатель на int. Это должно произойти сбой уже во время звонка Function в main! Я понятия не имею, что вы подразумеваете под name в этой строке в функции. Но если вы хотите распечатать целые числа, которые хранятся в массивах, на которые указывают (указатели на их первый элемент), вы можете сделать это так (сохраняя ваш код настолько, насколько я могу):

// don't forget the return type, mate. Also see below
void Function(int **ArrayPointer)
  {
    int i, j, index=0;
    for (i=0; i < 3; i++)
      {
        for (j=0; j < 2; j++)
          {
             // It does not print the data. It is not a string, 
             // but an int!
             printf("\nName: %d\n",  ArrayPointer[i][index++]);
          } 
        index=0;         //Counter reset to 0
        // no need to increment the pointer. that's what the indexing by i 
        // above does
        // ArrayPointer++;  
      }
  }

Я продолжаю проповедовать людям, задающим вопросы о разнице между указателем и массивом. Важно написать правильный код. Я надеюсь, что смогу помочь. В конце, немного о разнице между int[] и int*. Первый тип является неполным массивом, а второй - полным типом (указатель на int):

typedef int Single[]; // array of indeterminate size.
typedef int *Pointer; // pointer to int

Single s1 = { 1, 2, 3, 4 }; // works!
Pointer s2 = { 1, 2, 3, 4 }; // no no, doesn't work. s2 wants an address
Тип

s2 теперь имеет тип , отличный от типа int [] , поскольку при инициализации массива, который будет иметь неполный тип, массив s1 станет завершенным после определения. Имеет тип int[4]. Однако в списках параметров существует специальное правило, которое позволяет любому типу массива (даже полному!) Быть эквивалентным указателю на их первый аргумент. Таким образом:

void f(int *a) <=> void f(int a[]) <=> void f(int a[42]);
void f(int (*a)[42]) <=> void f(int a[][42]) <=> void f(int a[13][42])
// ...

Это потому, что вы не можете передавать массивы по значению. Компилятор использует , чтобы сделать типы массивов эквивалентными указателям на их первый элемент. То же самое касается функций:

void f(int a()) <=> void f(int (*a)())

Поскольку вы не можете передавать функции по значению (да, для меня это вообще не имеет смысла), компилятор использует для создания типа функции в списке параметров, эквивалентном указателю к этому типу функции.

0 голосов
/ 07 сентября 2009

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

int Data1[] = {10,10};
int Data2[] = {20,20};
int Data3[] = {30,30};

int *NameList[] = {Data1, Data2, Data3};

main()
{  
  Function(NameList); 
}

Function(int *ArrayPointer)
{ 
    int i, j, index=0;
    for (i=0; i < 3; i++)
      {
        for (j=0; j < 5; j++)
          {
             //It does not print the data
             printf("\nName: %d\n", *((int *)ArrayPointer[i] + index));
         index++;
          } 
        index=0;         //Counter reset to 0
      }
  }

Пояснение:

Когда вы передаете NameList в Function как указатель на целое число, передается адрес первого элемента массива, который является Data1 (адрес массива). Но поскольку этот адрес содержится в массиве целых чисел, он будет рассматриваться как целое число. Чтобы заставить его вести себя как адрес массива (или, в этом отношении указатель на int), вам нужно привести его к (int *). Вот что я сделал в:

printf("\nName: %d\n", *((int *)ArrayPointer[i] + index));

0 голосов
/ 02 января 2009

Paramod,

есть ли функция, которую нужно вызвать, которая принимает что-то вроде

void drawSprite(int *data, int rows, int cols)

Тогда вам нужно хранить все данные в одном фрагменте памяти. В вашем примере компилятор выделяет отдельный блок для каждой строки, а затем другой блок для хранения трех указателей на строки. Таким образом, массив хранится в 4 разных местах.

Вам нужен многомерный массив, а не массив массивов. Инициализируйте ваши данные так:

int data[3,2] = {{10,10},{20,20},{30,30}};

Тогда вы можете вызвать свою функцию следующим образом:

drawSprite(&data[0,0], 3, 2);

Использование многомерного массива помещает все элементы в один блок памяти. Преимущество в том, что вы можете передать piointer первому элементу, и вы знаете, где находятся все остальные элементы. Недостаток - все строки расположены одинакового размера.

0 голосов
/ 02 января 2009

Судя по вашему " ответу " (вы действительно должны были отредактировать свой оригинальный пост и добавить эту информацию), вы, вероятно, хотите что-то вроде этого:

void draw_all_sprites(Sprite *sprites, size_t num_sprites)
{
    Sprite *cur_sprite;
    size_t i;

    for(i = 0; i < num_sprites; ++i)
    {
        draw_sprite(cur_sprite);
        ++cur_sprite;
    }
}

Довольно простой цикл for для перебора элементов в массиве.

0 голосов
/ 02 января 2009
int Data1[]

имеет тип

int *

и

int *NameList[]

имеет тип

int **

У вас там двумерный массив. Скорее всего, вы имели в виду:

Function(int **ArrayPointer)

В этой заметке функции ANSI C / C89 / C99 имеют явный тип возврата (или void), например,

int main() { ... }
void Function() { ... }

Значение, на которое указывает ArrayPointer, является int, а не строкой. Таким образом

printf("\nName: %s",  ArrayPointer[index++]);

Должен быть написан как-то еще.

Третье: index == j в вашем коде. Таким образом, index может быть удалено в пользу j.

i и j, вероятно, здесь не являются хорошими именами переменных, поскольку ArrayPointer не является именем, описывающим список чего-либо.

Если вам нужна дополнительная помощь, пожалуйста, опубликуйте, что вы хотите сделать, потому что в вашем коде есть несколько ошибок (и странностей).

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