gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > Array pointer

#58331 - wiz - Sat Oct 22, 2005 6:54 pm

Hello!

I have an array which I am just playing around with to revise on pointers a bit more. I am currently going through the array a char at a time. This is how my array is set up:

Code:

#define LINESPERPAGE 4

const char *BOOK1[][LINESPERPAGE] =
{
   {
      "PARA 0 LINE 0",
      "PARA 0 LINE 1",
      "PARA 0 LINE 2",
      "PARA 0 LINE 3",
   },

   {
      "PARA 1 LINE 0",
      "PARA 1 LINE 1",
      "PARA 1 LINE 2",
      "PARA 1 LINE 3",
   },
};


I know I can read through this array like so, fixing myself to the array directly:
Code:

for (int EC = 0; EC < 14; EC++)
{
  // view each letter of PARA 0 LINE 0
  char Letter = BOOK1[0][0][EC];
}


But instead of the previous I would like to point to the array, so I could add more "BOOK" arrays and access any one, I thought something like this would work - but it doesnt. I found myself guessing with the pointers which I dont like to do
Code:

for (int EC = 0; EC < 14; EC++)
{
  Get a pointer to a BOOK array
  const char *pBOOK = &BOOK1;

  // view each letter of PARA 0 LINE 0
  char Letter = pBOOK[0][0][EC];
}


How should I be approaching this correctly? For now Im not looking for complete alternatives, just want to get my head around pointers thats all.

Thank you for any help!!

#58342 - sajiimori - Sat Oct 22, 2005 8:34 pm

First off, typing the name of an array returns the address of its first element. If you type BOOK1, that returns &BOOK1[0]. &BOOK1 is also equivalent.
Code:

char c = BOOK1[0][0][0];  // A single letter
char* cp = BOOK1[0][0];  // A line
char** cpp = BOOK1[0];  // A page
char*** cppp = BOOK1;  // The whole book

BTW, the contents of your strings suggest that the book is divided into paragraphs, but the LINESPERPAGE constant suggests that it's divided into pages. Just a semantic issue. :)

#58348 - Cearn - Sat Oct 22, 2005 9:14 pm

wiz wrote:
Code:

#define LINESPERPAGE 4

const char *BOOK1[][LINESPERPAGE] =
{
   {
      "PARA 0 LINE 0",
      "PARA 0 LINE 1",
      "PARA 0 LINE 2",
      "PARA 0 LINE 3",
   },

   {
      "PARA 1 LINE 0",
      "PARA 1 LINE 1",
      "PARA 1 LINE 2",
      "PARA 1 LINE 3",
   },
};

MSVC's debugger (you're not just testing this in a GBA environment are you?) gives me these memory locations:
Code:
:D748 book
:D748 book
  :D748 book[0]
    :908C "PARA 0 LINE 0"
    :9078 "PARA 0 LINE 1",
    :90D0 "PARA 0 LINE 2",
    :807C "PARA 0 LINE 3",
  :D758 book[1]
    :90BC "PARA 1 LINE 0"
   ... etc

So apparently, this means that BOOK1 is an array of quartets of pointers to strings (IOW, it's a matrix of char-pointers). Kinda surprised me too. If I hadn't tested it I would have sworn that the last index in the array would have been for the number of characters in each string. Oh well, live and learn. Note that if you have more than 4 lines/paragraph compilation will fail, and if you have less, you'll have an open space in the matrix.

Because of pointer and arrays are closely linked, you can use BOOK1 as a triple array because the first two indices give a char-pointer, and the last one gives the offset from that pointer. But once you start casting, there's no telling where you end up.
wiz wrote:
Code:
for (int EC = 0; EC < 14; EC++)
{
  Get a pointer to a BOOK array
  const char *pBOOK = &BOOK1;

  // view each letter of PARA 0 LINE 0
  char Letter = pBOOK[0][0][EC];
}

The first problem here is that BOOK1 is 3D-ish, while pBook is 1D. That's never gonna work unless you add extra casting code. The second if pBook is 1D, it expects all the characters to be consecutive, which is definitely not the case. 3D pointers wouldn't work you don't have 3 levels of pointers, you have a matrix (1st level) of char-pointers (2nd level). if you are certain that the paragraphs have a fixed number of lines, 2D pointers (1 for the matrix and 1 for the strings) will work:

Code:

const char **ppc= *book1;

int ip, il, ic;

// get #para's from somewhere else
for(ip=0; ip<2; ip++)  // para loop
{
    for(il=0; il<LPP; il++)  // line loop
    {
        for(ic=0; ppc[LPP*ip+il][ic]; ic++) // char loop
            cerr << ppc[LPP*ip+il][ic];
        cerr << endl;
    }
}

#58420 - sgeos - Sun Oct 23, 2005 2:15 pm

What are you trying to do? Whatever it is, there must be a less confusing way to do it.

-Brendan

#58694 - wiz - Tue Oct 25, 2005 1:20 pm

Thanks a lot guys, Cearn, thats a very detailed run down - very appreciate your time! sorry for taking so long to get back to you I need to re-read your post and understand it correctly :)

sgeos, cheers and you are right I shouldnt have named them as paragraphs.. If I want to confuse myself I need to do it properly ;)

To answer your question on what Im trying to do let me explain.

I plan on making a demo which at the start of every scene has a screen of text, (maximum of say 5 lines or so) The letters are displayed as sprites. I want to be able to have any amount of chars per line.

so in my head it looks like this:

BOOK1
|
PAGE1
|
LINE1
LINE2
...
|
PAGE2
|
LINE1
LINE2
...

BOOK2
etc.


This is how I created the array for a single book, because using a pointer I seem to be allowed to have any number of letters per line, and any number of pages.

Code:
const char *BOOK1[][LINESPERPAGE]


my displaying routine could loop through each line of a page by doing this:

for each line (say 0 to 5)
while current letter is not '\0' (to end of the line)
current letter = BOOK1[pagenumber][each line][letter pos++]
display the 'current letter'

which I have working, but as I said I could not make BOOK1 a variable as I needed to point to any book and page I want to display

I think Cearn has nailed it, so I will give that a go but any comments on my methods would be nice too :)

P.S. I am testing this is Borland C++ Builder.

#58762 - strager - Tue Oct 25, 2005 9:37 pm

I may be totally off... But, I would say... Try using typedefs for each 'type.' For example:
Code:
typedef char *line;
typedef line *page;
typedef page *book;


And for your array you would do:

Code:
#define MAX_BOOKS 256
book *myBooks[MAX_BOOKS];
int usedBooks = 0;

book myBook =
{
  "This is line 1 of page 1 of book 1",
  "Line 2",
  "Line three"
},
{
  "This is page 2",
  "Page 2 line 2",
  // ...
},
// ...


To add a book to myBooks:
Code:
int addBook(const book *addbook)
{
    /* Add the book to the list */
    myBooks[usedBooks] = (book *)addbook;

    /* Increment the book counter */
    usedBooks++;
};


Since you are using C++, you could make a book set class and have the oppropriate functions and such, which might be a little easier to manage.

#58771 - sajiimori - Tue Oct 25, 2005 10:27 pm

Does that even compile, strager? When you say book myBook = {...}, you're trying to create an anonymous array and store a pointer to its first element in myBook, which is a pointer type. Sadly, neither C nor C++ support array literals.

#58780 - strager - Tue Oct 25, 2005 11:27 pm

sajiimori wrote:
Does that even compile, strager? When you say book myBook = {...}, you're trying to create an anonymous array and store a pointer to its first element in myBook, which is a pointer type. Sadly, neither C nor C++ support array literals.


Oh, didn't realize that. Well, one way you could do it is by typecasting, so your initial declaration would look like what is in the origional post, and this could be added:
Code:
// Use either one, but I think the second is more safe
#define myBook ((book *)(arrayBook))
// -- or --
book *myBook = (book *)(arrayBook);

// -- or even... --
#define getBook(b) ((book *)(b))


I also noticed (in my last post) I didn't surround the data from myBook with brackets (only the pages)... Typo :-X .

#58787 - sajiimori - Wed Oct 26, 2005 1:08 am

The compiler is giving a type error for a reason. Casting gets rid of the error, but it doesn't solve the problem.

#58841 - legalize - Wed Oct 26, 2005 5:59 pm

sajiimori wrote:
First off, typing the name of an array returns the address of its first element. If you type BOOK1, that returns &BOOK1[0]. &BOOK1 is also equivalent.


&BOOK1[0] is a pointer to the first element in the array BOOK1.

&BOOK1 is a pointer to the array BOOK1.

These are entirely different things.

strager wrote:
I may be totally off... But, I would say... Try using typedefs for each 'type.' For example:
Code:
typedef char *line;
typedef line *page;
typedef page *book;


And for your array you would do:

Code:
#define MAX_BOOKS 256
book *myBooks[MAX_BOOKS];
int usedBooks = 0;

book myBook =
{
  "This is line 1 of page 1 of book 1",
  "Line 2",
  "Line three"
},
{
  "This is page 2",
  "Page 2 line 2",
  // ...
},
// ...


To add a book to myBooks:
Code:
int addBook(const book *addbook)
{
    /* Add the book to the list */
    myBooks[usedBooks] = (book *)addbook;

    /* Increment the book counter */
    usedBooks++;
};


Since you are using C++, you could make a book set class and have the oppropriate functions and such, which might be a little easier to manage.


Since he wants to display 1 of N predefined books, you can eliminate the array of book pointers to create the simplest thing that could possibly work. Also, he's not going to be changing the book text, so everything can be const.

Code:

const book myBooks[] =
{           // open array of books
    {       // open book 1
        {   // open page 1
            "This is line 1 of page 1 of book 1",
            "Line 2",
            "Last line of page 1"
        },  // close page 1
        {   // open page 2
            "This is line 1 of page 2 of book 1",
            "Line 2"
        }   // close page 2
    },      // close book 1
    {       // open book 2
        {   // open page 1
            "Line 1 of page 1 of book 2",
            "Line 2"
        }   // close page 1
    }       // close book 3
};          // close array of books


To know the number of books that were defined, you can use a simple sizeof() idiom:

Code:

#define NUM_BOOKS (sizeof(myBooks)/sizeof(myBooks[0]))


This is the size of the entire array divided by the size of the first element in the array, giving the number of elements in the array. Everything is evaluated at compile time into a constant value for an array like this with a good compiler like gcc.

#58846 - sajiimori - Wed Oct 26, 2005 6:40 pm

Oh right, type-wise they're different, though value-wise they are the same. Personally, I've never had a use for the pointer-to-array type.

It should probably be noted that your example assumes that the book type is padded out to the maximum number of pages and the maximum number of lines per page. That could turn Alice's Adventures in Wonderland to Moby Dick. ;)