0
typedef struct square
{
    int i;
    char c;
} Square;


Square** initializeMatrix(void);
void printMatrixNumbers(Square**);
void printMatrixLetters(Square**);
void shuffleMatrix(Square**);

Square* initialize1DMatrix(void);
void print1DMatrixLetters(Square*);
void print1DMatrixNumbers(Square*);
void shuffle1DMatrix(Square*);



int main(void)
{
    srand(time(NULL));

    Square** matrix = initializeMatrix();

    while(1)
    {
        printf("Print which set?: ");
        printf("\n1. letters\n2. numbers\n3. shuffle matrix\n4. move to 1D    matrix");
        printf("\n>");
        int choice;
        scanf("%d", &choice);

        if(choice == 1)
        {
            printMatrixLetters(matrix);
        }
        else if(choice == 2)
        {
            printMatrixNumbers(matrix);
        }
        else if(choice == 3)
        {
            shuffleMatrix(matrix);
        }
        else if(choice == 4)
        {
            break;
        }
        else
        {
            printf("Didn't understand that input. Try again\n\n");
        }
    }

    Square* matrix2 = initialize1DMatrix();
    printf("\n\nNow for the 1D array:\n\n");

    while(1)
    {
        int choice;
        printf("Print which set?: ");
        printf("\n1. letters\n2. numbers\n3. shuffle matrix\n4. quit");
        printf("\n>");
        scanf("%d", &choice);

        if(choice == 1)
        {
            print1DMatrixLetters(matrix2);
        }
        else if(choice == 2)
        {
            print1DMatrixNumbers(matrix2);
        }
        else if(choice == 3)
        {
            shuffle1DMatrix(matrix2);
        }
        else if(choice == 4)
        {
            break;
        }
        else
        {
            printf("Didn't understand that input. Try again\n\n");
        }
    }

     return 0;
 }




Square** initializeMatrix()
 {
     //this will be used to randomize the matrix. See below for more info.
     char letters[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',  'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'}; 


    int row, column;


    Square** matrix;

This double pointer was provided. It's supposed to point to something but I'm not sure what it should point to. Any insight or explanation would be incredibly helpful. I've tried looking up double pointers and understand, for example that if you have a list of characters you could use something like *word, and from there if you wanted a sentence you could do **sentence which points to words. Not sure how this carries over though.

    for(row = 0; row < ROWS; row++)
    {

supposed to be doing something with this, not sure what yet, though. Is this where the array of pointers gets its own element array? }

        for(row = 0; row < ROWS; row++)
    {
            for(column = 0; column < COLUMNS; column++)
            {

Here is where I need to generate the random numbers and letters and then give that number and character to the matrix. Below, I'm getting expected identifier or ')' before ',' token. Why is this?

                    srand(time(NULL));
                    Square.i[row][column]=rand()%10;


             }

     }      




return matrix;
}
Joe
  • 1
  • 3

3 Answers3

2

Ok, it is obvious, you need help getting over the first part of C using/referencing dynamically allocated memory, so let's look at the basics. But, before we even look at code, let's talk about how you are going to compile it. You need to enable warnings when you compile, and then eliminate all warnings before you consider your code done. The warnings are there to help you. At minimum you want to enable -Wall -Wextra when using gcc, you can check for the equivalent with other compilers. Your compile string will look similar to:

gcc -Wall -Wextra -g -o square square.c

The -g will generate symbols for debugging with gcc. When you are done debugging you will want to replace -g with your desired optimization level 0 (zero, the default), or 1, 2, 3, fast. You specify the option with a capital -O (Oh, not zero) (e.g. -O3 or -Ofast (gcc 4.6 and newer)).

Now knowing how you will build your code, let's look at how to write it. First, in C, there are no 2D arrays. There are only ways to simulate indexing for 2D arrays. When you are using an array of pointers to type (e.g. Square **matrix), the way to simulate a 2D array is to declare and allocate an array of pointers to type Square:

Square **matrix = NULL;
matrix = calloc (ROWS, sizeof *matrix);

This will declare ROWS number of pointers to matrix of type Square*. Then, for each pointer, you allocate a block of memory to hold the desired number of struct Square:

for (row = 0; row < ROWS; row++)
{
    matrix[row] = malloc (COLS * sizeof **matrix);
    ...
}

You have now declared ROWS number of pointers to arrays of COLS number type Square. This allows you to simulate a 2D array even though there is no requirement that any of the arrays are contiguous in memory.

Note: calloc was used to allocate the pointers. calloc both allocates and initializes to NULL (or 0). Every time you allocate a block of memory, you need to validate that the allocation was successful. You do this by checking the return from malloc, calloc, or realloc -- every time. E.g.:

matrix = calloc (ROWS, sizeof *matrix);
if (!matrix) {
    fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
    exit (EXIT_FAILURE);
}

You can create a helper function to allocate/check and return a pointer to the new memory block to keep your code tidy.

Note2: after you allocate and validate a block of memory, it is your responsibility to (1.) preserve a pointer to the starting address of that block of memory so (2.) that block of memory can be freed when you no longer need it.

For your 1D array, things are much simpler, you simply allocate storage for the number of type Square you need. E.g.:

matrix = calloc (ROWS * COLS, sizeof *matrix);

You can simulate a 2D array from this allocation as well by simply creating logic that allows 2D array type indexing to refer to any location within your contiguous array. (it looks like matrix[row*ROWS+col] where 0 <= row < ROWS). Though not part of the example below, if you did want to simulate a 2D array from your matrix2, then for sake of completeness you could implement the print numbers part as follows:

void print1DMatrixAs2DNumbers (Square *matrix)
{
    if (!matrix) return;

    int row, col;

    printf ("\n simulated 2D array numbers are:\n\n");
    for (row = 0; row < ROWS; row++) {
        for (col = 0; col < COLS; col++)
            printf ("  %4d", matrix[row * ROWS + col].i);
        putchar ('\n');
    }
    putchar ('\n');
}

What does (1.) in Note2 mean? It means you must pay particular attention to not do something like the following:

while (1) {
    ...
    matrix++;
}

When you are done with the loop, what points to the start of the block of memory you originally allocated? Nothing. If you don't have the starting address, that memory can no longer be freed. If you find yourself in that situation, create a pointer to matrix and use that in the loop. (e.g. Square *p = matrix; then while (1) {... p++;} )

Those are the basics behind doing what it is you are trying to do. The remainder is just syntax and sorting out your program logic. Yes, I know you need help there too.

The following is an example implimenting your code. It is intended to show you how to put the pieces together, not do it for you. C is an extremely elegant and flexible low-level language that provides power and control over the machine that few languages, other than assembler, can provide. There is learning curve associated with any language, C is no different. However, unlike other higher level languages, C gives you the flexibility to do just about anything the syntax allows. There are no protections built into functions protecting against writing beyond the end of arrays or writing to areas of memory after an attempted allocation fails. Learning C, the responsibility is on you to learn C to that level, to protect against the forseeable problems than come for the power you are given.

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROWS 8
#define COLS 8

typedef struct square
{
    int i;
    char c;
} Square;

Square **initializeMatrix (void);
void printMatrixNumbers (Square**);
void printMatrixLetters (Square**);
void shuffleMatrix (Square**);

Square *initialize1DMatrix (void);
void print1DMatrixLetters (Square*);
void print1DMatrixNumbers (Square*);
void shuffle1DMatrix (Square*);

int main (void)
{
    srand (time (NULL));

    Square **matrix = initializeMatrix();

    while (1)
    {
        int choice;
        printf ("\nPrint which set?: \n\n"
                " 1. letters\n"
                " 2. numbers\n"
                " 3. shuffle matrix\n"
                " 4. move to 1D matrix\n"
                " > ");
        scanf ("%d", &choice);

        if(choice == 1)         printMatrixLetters (matrix);
        else if(choice == 2)    printMatrixNumbers (matrix);
        else if(choice == 3)    shuffleMatrix (matrix);
        else if(choice == 4)    break;
        else printf("Didn't understand that input. Try again\n");
    }

    Square *matrix2 = initialize1DMatrix();
    printf ("\nNow for the 1D array:\n\n");

    while (1)
    {
        int choice;
        printf ("\nPrint which set?: \n\n"
                " 1. letters\n"
                " 2. numbers\n"
                " 3. shuffle matrix\n"
                " 4. quit\n"
                " > ");
        scanf ("%d", &choice);

        if(choice == 1)         print1DMatrixLetters (matrix2);
        else if(choice == 2)    print1DMatrixNumbers (matrix2);
        else if(choice == 3)    shuffle1DMatrix (matrix2);
        else if(choice == 4)    break;
        else printf("Didn't understand that input. Try again\n");
    }

    /* free simulated 2D matrix */
    size_t i;
    for (i = 0; i < ROWS; i++)
        free (matrix[i]);
    free (matrix);

    /* free matrix2 */
    free (matrix2);

    return 0;
}

Square **initializeMatrix ()
{
    /* unless you can't have a null-terminator, this is fine */
    char letters[] = "abcdefghijklmnopqrstuvwxyz"; 
    int row, col;

    Square **matrix = NULL;

    /* allocate ROWS number of pointers to struct Square 
     * 'calloc' allocates and initializes NULL, you must then
     * validate your allocation by checking the return.
     */
    matrix = calloc (ROWS, sizeof *matrix);
    if (!matrix) {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__);
        exit (EXIT_FAILURE);
    }

    /* allocate COLS number of struct Square and validate */
    for (row = 0; row < ROWS; row++)
    {
        matrix[row] = malloc (COLS * sizeof **matrix);

        if (!matrix) {
            fprintf (stderr, "%s() error: virtual memory exhausted.\n", 
                    __func__);
            exit (EXIT_FAILURE);
        }

        for (col = 0; col < COLS; col++)
        {
            /* fill i with random number between 0 - 999 */
            matrix[row][col].i = rand() % 1000;

            /* fill c with random letter 'a-z' */
            matrix[row][col].c = letters[rand() % 26];
        }
    }

    return matrix;
}

Square *initialize1DMatrix ()
{
    /* unless you can't have a null-terminator, this is fine */
    char letters[] = "abcdefghijklmnopqrstuvwxyz"; 
    int i;

    Square *matrix = NULL;

    /* allocate memory for ROWS * COLS struct Square
     * and validate
     */
    matrix = calloc (ROWS * COLS, sizeof *matrix);

    if (!matrix) {
        fprintf (stderr, "%s() error: virtual memory exhausted.\n", 
                    __func__);
        exit (EXIT_FAILURE);
    }

    for (i = 0; i < ROWS * COLS; i++)
    {
        /* fill i with random number between 0 - 999 */
        matrix[i].i = rand() % 1000;

        /* fill c with random letter 'a-z' */
        matrix[i].c = letters[rand() % 26];
    }

    return matrix;
}

void printMatrixNumbers (Square **matrix)
{
    if (!matrix) return;

    int row, col;

    printf ("\n simulated 2D array numbers are:\n\n");
    for (row = 0; row < ROWS; row++) {
        for (col = 0; col < COLS; col++)
            printf ("  %4d", matrix[row][col].i);
        putchar ('\n');
    }
    putchar ('\n');
}

void printMatrixLetters (Square **matrix)
{
    if (!matrix) return;

    int row, col;

    printf ("\n simulated 2D array letters are:\n\n");
    for (row = 0; row < ROWS; row++) {
        for (col = 0; col < COLS; col++)
            printf ("  %4c", matrix[row][col].c);
        putchar ('\n');
    }
    putchar ('\n');
}

void shuffleMatrix (Square **matrix)
{
    if (!matrix) return;

    fprintf (stderr, "%s() warning: not yet implemented.\n", __func__);
}

void print1DMatrixNumbers (Square *matrix)
{
    if (!matrix) return;

    size_t i;

    printf ("\n matrix2 numbers are:\n\n");
    for (i = 0; i < ROWS * COLS; i++)
        printf ("  matrix2[%2zu] : %4d\n", i, matrix[i].i);
    putchar ('\n');
}

void print1DMatrixLetters (Square *matrix)
{
    if (!matrix) return;

    size_t i;

    printf ("\n matrix2 letters are:\n\n");
    for (i = 0; i < ROWS * COLS; i++)
        printf ("  matrix2[%2zu] : %c\n", i, matrix[i].c);
    putchar ('\n');
}

void shuffle1DMatrix (Square *matrix)
{
    if (!matrix) return;

    fprintf (stderr, "%s() warning: not yet implemented.\n", __func__);
}

Compile

gcc -Wall -Wextra -o bin/square square.c

Use/Output

$ ./bin/square

Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. move to 1D matrix
 > 2

 simulated 2D array numbers are:

   180   468   335   205   480   606    40   276
   360   581   824   731    59   827   573   708
   837    18   557   109   234   348   255    54
   527   479    60   174   891   799   868   922
    35   230   867   335   406   375   660   629
   416   243   670   948   123   377   607    48
   943   291   617   263    14    37   419   565
   126   664   578   357   712    44   738    17


Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. move to 1D matrix
 > 1

 simulated 2D array letters are:

     l     a     f     q     l     e     x     y
     x     p     y     w     p     w     c     t
     u     c     h     g     l     q     a     t
     n     m     a     p     v     s     f     l
     i     d     l     l     x     j     r     z
     q     u     t     j     x     p     p     e
     s     o     s     e     c     q     s     c
     d     c     k     p     p     p     j     c


Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. move to 1D matrix
 > 4

Now for the 1D array:


Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. quit
 > 2

 matrix2 numbers are:

  matrix2[ 0] :  371
  matrix2[ 1] :  844
  matrix2[ 2] :  287
  matrix2[ 3] :   69
  matrix2[ 4] :   98
  matrix2[ 5] :  327
  matrix2[ 6] :  125
  matrix2[ 7] :  706
  matrix2[ 8] :   54
  matrix2[ 9] :  400
  ...
  matrix2[59] :  504
  matrix2[60] :  655
  matrix2[61] :  604
  matrix2[62] :  583
  matrix2[63] :  597


Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. quit
 > 1

 matrix2 letters are:

  matrix2[ 0] : f
  matrix2[ 1] : h
  matrix2[ 2] : u
  matrix2[ 3] : r
  matrix2[ 4] : a
  matrix2[ 5] : u
  matrix2[ 6] : b
  matrix2[ 7] : f
  matrix2[ 8] : y
  matrix2[ 9] : e
  ...
  matrix2[60] : a
  matrix2[61] : u
  matrix2[62] : z
  matrix2[63] : h


Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. quit
 > 4

Memory Leak/Error Check

In any code your write that dynamically allocates memory, it is imperative that you use a memory error checking program. For Linux valgrind is the normal choice. There are so many subtle ways to misuse a block of memory that can cause real problems, the is no excuse not to do it. There are similar memory checkers for every platform. They are simple to use. Just run your program through it.

$ valgrind ./bin/square
==9866== Memcheck, a memory error detector
==9866== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==9866== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==9866== Command: ./bin/square
==9866==

Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. move to 1D matrix
 > 2

 simulated 2D array numbers are:

   299   713   762   909   504   705   697   846
   600   735   239     2   870   258   998   155
   819    88   649   688   921   890     3   657
   418    52   761   739    17   612   159   664
   340   264   454   848    49   345   179   359
   747   958   523   845   398   259   928   240
   380   963   808   561   253   614   613   733
   442   222   740   209   228   697   743   777

<snip>

Print which set?:

 1. letters
 2. numbers
 3. shuffle matrix
 4. quit
 > 4
==9866==
==9866== HEAP SUMMARY:
==9866==     in use at exit: 0 bytes in 0 blocks
==9866==   total heap usage: 10 allocs, 10 frees, 1,088 bytes allocated
==9866==
==9866== All heap blocks were freed -- no leaks are possible
==9866==
==9866== For counts of detected and suppressed errors, rerun with: -v
==9866== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

A pointer points to a block of memory. In order to use one as an array, you must allocate memory.

Square *ptr = malloc(sizeof(Square) * 10)

I have created an array of 10 Square and ptr points to the first Square of this array. Accessing the third Square is done by writing ptr[2].

Moving on to double pointers. They point to other pointers. Imagine a matrix.

Square **p1;
**p1 = malloc(sizeof(Square) * 10)
*p1 = malloc(sizeof(Square*) * 10)

p1[0] points to the pointer that points to the first array. p1[1] points to the second one and so on. In order to understand pointers better you can think of them as n-dimensional arrays, where n is the number of stars.

  • Please don't cast the return of `malloc` and friends: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc – Jens Gustedt Oct 08 '15 at 19:45
  • @Jens Gustedt Thank you for the advice! – Razvan Meriniuc Oct 08 '15 at 19:50
  • Ohhh okay. I understand. Why do we need to point to the pointer? Why couldn't we simply just use the pointer address? – Joe Oct 08 '15 at 21:44
  • @Joe Because otherwise you can't hold a matrix. A matrix is layered arrays, but if you don't keep all the beginnings of the arrays they are independent from each other. Imagine **Square like a vertical array, each box containing a pointer, and from every box an arrow to an horizontal array. – Razvan Meriniuc Oct 09 '15 at 05:40
-1

you first have to define ROWS and COLUMNS

then allocate memory for the matrix:

matrix=malloc(sizeof(quare)* ROWS*COLUMNS);

last correct this Square.i[row][column]=rand()%10; to this matrix[row][column].i=rand()%10;

milevyo
  • 2,165
  • 1
  • 13
  • 18
  • Thanks! This Square[row][column].i=rand()%10; still gets me the same error as before: expected identifier before '['. Why is this? – Joe Oct 08 '15 at 21:41
  • sorry please correct change 'Square' to 'matrix'. thank you for the remark – milevyo Oct 08 '15 at 21:45
  • Do **not** cast the return of `malloc`. It is nothing more than a memory address. It does not have a `'type'`. The proper allocation is `matrix = malloc (ROWS * sizeof *matrix)` then `matrix[i] = malloc (COLUMNS * sizeof **matrix)`. You then assign `matrix[i][j]` – David C. Rankin Oct 09 '15 at 05:13