Here I'm trying to allocate the memory dynamically to create multi-dimensional.
So I declared a pointer to pointer to pointer :
int ***array ;
And allocated memory for variable array
array = (int***)malloc((sizeof(int) * 2));
This is my code !
void main(void)
{
int matrices, rows, columns;
int ***array;
printf("\n\n HOW MANY MATRICES YOU TO CREATE ? : ");
scanf("%d",&matrices);
array = (int***)malloc((sizeof(int) * matrices));
printf("\n HOW MANY ROWS YOU TO CREATE ? : ");
scanf("%d",&rows);
printf("\n HOW MANY COLUMNS YOU TO CREATE ? : ");
scanf("%d",&columns);
for(int i = 1; i <= matrices; i++)
{
printf("\n Enter %d - matrix! ",i);
for(int j = 1; j <= columns; j++)
{
for(int k = 1; k <= rows; k++)
{
printf("\n Enter element [%d[%d] : ",j,k);
scanf("%d",&array[i][j][k]);
}
}
}
//printing two matrices elements!!!
for(int l = 1; l <= matrices; l++)
{
printf("\n MATRIX - %d !! \n",l);
for(int m = 1; m <= columns; m++)
{
for(int n = 1; n <= rows; n++)
{
printf("%d\t",array[l][m][n]);
}
printf("\n");
}
}
}
But when I try to print the elements of the both matrices, here only second matrix elements are displayed on output for both matrices and very first element in both matrices are displayed with ' 0 ' .
Example :
Input :
First matrix
1 2 3
4 5 6
second matrix
9 8 7
3 5 2
Output :
First matrix
0 8 7
3 5 2
second matrix
0 8 7
3 5 2
I'm new to this site, any mistakes please comment !!
Just use Variable Length Array (VLA) with dynamic storage.
int (*array)[rows + 1][cols + 1] = malloc(sizeof(int[matrices + 1][rows + 1][cols + 1]));
Using VLAs is a lot simpler and more performant.
Adding 1 to each dimension let you address array from index 1 and prevents program from Undefined Behaviour (UB) when accessing element array[matrixes][rows][cols].
However, it is BAD practice because arrays in C are indexed from 0. Other approach will confuse other users of your code.
Therefore, I strongly encourage you to index arrays from 0 and remove all "+ 1"s.
So the correct allocation code should be:
int (*array)[rows][cols] = malloc(sizeof(int[matrices][rows][cols]));
And update all loops to form:
for(i = 0; i < matrices ; i++)
Finally, free the array when it is no longer used.
free(array)
You have not SegFaulted only by happy accident, and due to the fact that the size of a pointer doesn't change. So where you allocate for int* where you should be allocating for int**, the size of your allocation isn't affected (by happy accident...)
You generally want to avoid becoming a 3-Star Programmer, but sometimes, as in this case, it is what is required. In allocating for any pointer, or pointer-to-pointer, or in this case a pointer-to-pointer-to-pointer, understand there is no "array" involved whatsoever.
When you declare int ***array; you declare a single pointer. The pointer then points to (holds the address of) a block of pointers (type int**) that you allocate. You allocate storage for matricies number of int** pointers as input by the user.
Each matrix is type int**, so you must allocate a block of memory containing rows number of pointer for each matrix.
Finally you allocate cols number of int (type int*) for each and every row in each and every matrix.
So your collection of matricies is an allocated block of pointers with one pointer for each matrix. Then each matrix is an allocate block of pointers with one pointer for every row in that matrix. Finally you allocate a columns worth of int for each an every row pointer for each and every matrix.
Visually your allocation and assignment would resemble the following:
array (int***)
|
+ allocate matricies number of [Pointers]
|
+----------+
| array[0] | allocate rows number of [Pointers] for each matrix
+----------+ assign to each pointer in array block
| array[1] |
+----------+ array[2] (int**)
| array[2] | <======= +-------------+
+----------+ | array[2][0] |
| .... | +-------------+ allocate cols no. of [int]
| array[2][1] | for each allocated row pointer
+-------------+
| array[2][2] | <=== array[2][2] (int*)
+-------------+ +----------------+
| ... | | array[2][2][0] |
+----------------+
| array[2][2][1] |
+----------------+
| array[2][2][2] |
+----------------+
| ... |
In order to always keep the type-size of each allocation correct, simply use the dereferenced pointer to set the type-size. For example when allocating for array (int***) you would use:
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
When allocating for each array[i], you would use:
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
Finally when allocating for each block of int for each row, every array[i][j], you would use:
array[i][row] = malloc (cols * sizeof *array[i][row]);
If you always use the dereference pointer to set type-size, you will never get it wrong.
Following the diagram above through and just taking each allocation in turn (and validating EVERY allocation), you could write your allocation and free routines similar to:
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
The complete example that allocates for the number of matricies with the number of rows and columns entered by the user would be:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
int ***array = NULL,
matrix,
rows,
cols;
fputs ("no. of matricies: ", stdout);
if (scanf ("%d", &matrix) != 1) /* validate EVERY input */
return 1;
fputs ("no. of rows : ", stdout);
if (scanf ("%d", &rows) != 1) /* ditto */
return 1;
fputs ("no. of cols : ", stdout);
if (scanf ("%d", &cols) != 1) /* ditto */
return 1;
/* use dereferenced pointer for type-size */
array = malloc (matrix * sizeof *array); /* allocate matrix int** */
if (!array) { /* validate EVERY allocation */
perror ("malloc-array");
return 1;
}
for (int i = 0; i < matrix; i++) {
array[i] = malloc (rows * sizeof *array[i]); /* array[i] int** pointers */
if (!array[i]) { /* validate */
perror ("malloc-array[i]");
return 1;
}
for (int row = 0; row < rows; row++) {
/* allocate cols int per-row in each matrix */
array[i][row] = malloc (cols * sizeof *array[i][row]);
if (!array[i][row]) {
perror ("malloc-array[i][row]");
return 1;
}
}
}
/* fill matricies with any values */
for (int i = 0; i < matrix; i++)
for (int j = 0; j < rows; j++)
for (int k = 0; k < cols; k++)
array[i][j][k] = j * cols + k + 1;
/* display each matrix and free all memory */
for (int i = 0; i < matrix; i++) {
printf ("\nmatrix[%2d]:\n\n", i);
for (int j = 0; j < rows; j++) {
for (int k = 0; k < cols; k++)
printf (" %2d", array[i][j][k]);
putchar ('\n');
free (array[i][j]); /* free row of int (int*) */
}
free (array[i]); /* free matrix[i] pointers (int**) */
}
free (array); /* free matricies pointers (int***) */
}
(note: you free the memory for each block of int before freeing the memory for the block of row pointers in each matrix before freeing the block of pointers to each matrix)
Example Use/Output
$ ./bin/allocate_p2p2p
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
Memory Use/Error Check
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to ensure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
$ valgrind ./bin/allocate_p2p2p
==9367== Memcheck, a memory error detector
==9367== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9367== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==9367== Command: ./bin/allocate_p2p2p
==9367==
no. of matricies: 4
no. of rows : 4
no. of cols : 5
matrix[ 0]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 1]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 2]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
matrix[ 3]:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
16 17 18 19 20
==9367==
==9367== HEAP SUMMARY:
==9367== in use at exit: 0 bytes in 0 blocks
==9367== total heap usage: 23 allocs, 23 frees, 2,528 bytes allocated
==9367==
==9367== All heap blocks were freed -- no leaks are possible
==9367==
==9367== For counts of detected and suppressed errors, rerun with: -v
==9367== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Look things over and let me know if you have further questions.
Since you are using pointer to pointer to pointer. You need to dynamically allocate memory at all stages. At the first stage after you've asked number of matrices. It should be,
array = (int***)malloc (sizeof(int**) * matrices);
Since you are allocating matrices which are int**. Then after asking number of rows, for each matrix you need to allocate that,
for(i=1 ; i <= matrices ; i++)
array[i-1] = (int**)malloc (sizeof(int*)*ROWS);
Finally you need to allocate memory for each row. So,
for(i=1 ; i <= matrices ; i++)
for(j=1 ; j <= ROWS ; j++)
array[i-1][j-1] = (int*)malloc (sizeof(int)*COLS);
After this you can take inputs at your leisure the way you did. Try this, it should work. If it doesn't, there should be some other problem.
In C, avoid the model of
pointer = (some_type *) malloc(n * sizeof(some_type)); // Avoid
Instead of allocating to the type, allocate to the referenced object and drop the unneeded cast. Form the size computation with the widest type first. sizeof operator returns a type of size_t.
pointer = malloc(sizeof *pointer * n); // Best
This is simpler to code right (OP's (sizeof(int) * matrices) was incorrect and too small), review and maintain.
Robust code check for allocation errors.
if (pointer == NULL) {
fprintf(stderr, "Out of memory\n"); // Sample error code, adjust to your code's need
exit(-1);
}
Allocate memory for the matrix data, something OP's code did not do.
array = malloc(sizeof *array * matrices);
// Error checking omitting for brevity, should be after each malloc()
// Use zero base indexing
// for(int i = 1; i <= matrices; i++) {
for (int m = 0; m < matrices; m++) {
array[m] = malloc(sizeof *array[m] * rows);
for (int r = 0; r < rows; r++) {
array[m][r] = malloc(sizeof *array[m][r] * columns);
}
}
// Now read in data
// Use data
// Free when done
for (int m = 0; m < matrices; m++) {
for (int r = 0; r < rows; r++) {
free(array[m][r]);
}
free(array[m]);
}
free(array);
Better code would use size_t for the array dimension's type than int, yet int will do for small programs.
Related
I have an input file like this:
3
7 12 1
1 3 3
2 3 0
12 0 11
7 4 1
1 0 0
The first character tells me the size of the square matrix. Then I have a word that indicates the action to be done and then the matrix. I can't find a way to read the first matrix, use it, deallocate it and then move on to the second and so on. Any help? (I'm using c)
I think I found a solution to allocate the matrix using this code:
int** Matrix;
int n, i;
fscanf(Data, "%d", &n);
Matrice = (int**)calloc(n, sizeof(int*));
for(i=0; i<4; i++)
Matrix[i] = (int*)calloc(n, sizeof(int*));
But this works for the first matrix and I don't know how to treat next matrices to not waste too much memory...
Use a while loop that stops when you reach the end of the file, and create a new matrix with each iteration. This way, you can free each matrix before creating a new one.
(To simplify, this example code works without "ReadMatrix" rows in the input file)
int stop = 0;
while(stop != 1){
Matrix = (int**)calloc(n, sizeof(int*));
for(i=0; i<n; i++) {
Matrix[i] = (int*)calloc(n, sizeof(int));
for(int j=0; j<n; j++) {
if(fscanf (Data, "%d", &Matrix[i][i]) == EOF)
stop = 1;
}
}
//Use the matrix here
//...
for(int i=0; i<n; i++)
free(Matrix[i]);
free(Matrix);
}
Example input:
3
7 12 1
1 3 3
2 3 0
12 0 11
7 4 1
1 0 0
so I am new to C programming and allocating memory. So I have written a program that does matrix multiplication. I have allocated memory for the 1d array within the 2d array for matrix 1 and same with matrix 2. Below is my code and I do not understand why I am getting a heap buffer overflow. Input contains a file that contains dimensions and components of both matrixes. An example file format might contain the following format
3 3
1 2 3
4 5 6
7 8 9
3 3
1 2 3
4 5 6
7 8 9
The first line 3 and 3 would mean 3 rows and 3 columns of matrix 1. Hence when reading it from the file it would be stored in rows1 and columns1. Next, 1-9 would be contained in the first matrix. 3 and 3 would be 3 rows of matrix 2 and 3 columns of matrix 2. Hence it would be stored in rows2 and columns2. All these numbers are separated by tabs. The above file was the one of many I tested and it got my a heap buffer overflow.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
void print(int** square, int rows,int columns);
int main(int argc, char** argv) {
FILE *fp = fopen(argv[1], "r");
if (fp == NULL) {
printf("error\n");
return 0;
}
int rows1 = 0; int columns1 = 0; int num = 0;
fscanf(fp, "%d", &rows1);
fscanf(fp, "%d", &columns1);
int** square = (int**) malloc(sizeof(int*) * rows1);
for (int i = 0; i < rows1; i++) {
square[i] = (int*) malloc(sizeof(int) * columns1);
}
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns1; j++) {
fscanf(fp, "%d", &num);
square[i][j] = num;
}
}
int rows2 = 0; int columns2; int num2 = 0;
fscanf(fp, "%d", &rows2);
fscanf(fp, "%d", &columns2);
int** square2 = (int**) malloc(sizeof(int*) * rows2);
for (int i = 0; i < rows2; i++) {
square2[i] = (int*) malloc(sizeof(int) * columns2);
}
for (int i = 0; i < rows2; i++) {
for (int j = 0; j < columns2; j++) {
fscanf(fp, "%d", &num2);
square2[i][j] = num2;
}
}
if (columns1 != rows2) {
printf("bad-matrices\n");
return 0;
}
int ans = 0;
int** answer = (int**) malloc(sizeof(int*) * rows1);
for (int i = 0; i < rows1; i++) {
answer[i] = (int*) malloc(sizeof(int) * columns2);
}
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns2; j++) {
for (int k = 0; k < rows2; k++) {
ans += square[i][k] * square2[k][j];
}
answer[i][j] = ans;
ans = 0;
}
}
print(answer, rows1, columns2);
fclose(fp);
return 0;
}
void print(int** square, int rows, int columns) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
printf("%d\t", square[i][j]);
}
printf("\n");
}
return;
}
Outcome:
==31599== ERROR: AddressSanitizer: heap-buffer-overflow on address.....
"heap-buffer-overflow" means that you created a buffer of a certain size, but tried to access beyond the bounds of the buffer. This normally means that either you have a loop that's using the wrong value for an upper bound, or that one of your buffers is not actually the size that you think it is.
It's hard to tell for sure what's going on here. The code copy/pasted into my gcc appears to work as expected (I don't have access to AddressSanitizer at the moment though). The first thing I noticed about your code was that it uses values read from the input file both for buffer sizes and for loop bounds without any sort of sanity checking. My recommendation is to step through this code in your debugger and make sure that the values that get read from disk and the computed buffer sizes are all what you expect them to be. All it takes is for one of those scanf() calls to encounter something unexpected, return zero, and throw all of your computations off.
Also, it might be useful if you include the entire output of the compiler's error message (dont' forget to compile in debug mode). The AddressSanitizer output normally includes a stack trace that can point you to the line number where the problem occurred. Also useful would be the name and version number of your compiler, plus whatever command-line options you're using.
Using malloc
First, your code is fine, but that doesn't meant is doesn't contain problems. First, let's look at your use of malloc, e.g.
int** answer = (int**) malloc(sizeof(int*) * rows1);
There is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?. Further, and this is more style than anything else, the '*'s showing the levels of indirection go with the variable not the type. Why?
int* a, b, c;
That certainly does not declare 3-pointers to int. It declares a single pointer and two integers, e.g.
int *a, b, c;
When setting the type-size for the allocation, if you always use the dereferenced pointer itself, you will never get your type-size wrong, e.g.
int **answer = malloc (rows1 * sizeof *answer);
If Allocate it, You Must Validate It, & It's Up To You to free it
For every allocation, you should check that the pointer returned by malloc, calloc, realloc is not NULL. Allocation functions do fail when you run out of memory. Always check.
In any code you write that dynamically allocates memory, you have 2 responsibilities regarding any block of memory allocated: (1) always preserve a pointer to the starting address for the block of memory so, (2) it can be freed when it is no longer needed.
It is imperative that you use a memory error checking program to insure you do not attempt to access memory or write beyond/outside the bounds of your allocated block, attempt to read or base a conditional jump on an uninitialized value, and finally, to confirm that you free all the memory you have allocated.
For Linux valgrind is the normal choice. There are similar memory checkers for every platform. They are all simple to use, just run your program through it.
Always confirm that you have freed all memory you have allocated and that there are no memory errors.
Simply declare a function to free your pointer arrays, and pass each to the free function along with the row-count before your program exits, e.g.
void freearr (int **a, int rows)
{
for (int i = 0; i < rows; i++)
free (a[i]);
free (a);
}
and
...
fclose(fp);
freearr (square, rows1);
freearr (square2, rows2);
freearr (answer, rows1);
return 0;
Why Do I Get: ERROR: AddressSanitizer: heap-buffer-overflow on address.....?
This is more a result of your compiler telling you to double-check your use of array bounds. Specifically here it most likely results from:
int answer = malloc (rows1 * sizeof *asnwer);
for (int i = 0; i < rows1; i++)
answer[i] = malloc (columns2 * sizeof *answer[i]);
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < columns2; j++) {
for (int k = 0; k < rows2; k++) {
ans += square[i][k] * square2[k][j];
}
answer[i][j] = ans;
Note: how answer is sized using the bounds of rows1 and columns2, while square is allocated using rows1, columns1 and square2 with rows2, columns2. Your compiler can help you spot potential heap overflow by keeping track of the variables used to size the allocation. Some compilers are better than others at this.
If the compiler cannot determine that the limits you are using to iterate over your array, it can throw the warning about potential buffer overflow. (all it should care about is the value of the limits used, but like I said, some compilers are better than others...)
After allocating with the limits set out above, you then proceed to iterate over the pointer arrays with different limits that were read into separate and unrelated variables. Using rows1, columns2 to iterate over square, square2 & answer. Think about it, while you know columns1 == columns2, then compiler has no guarantee of that. Same for rows2 == rows1.
Your compiler has no guarantee that using rows1 with square2 won't write beyond its allocated size. Likewise it has no guarantee that using columns2 won't violate the bounds of square. Your test of columns1 != rows2 doesn't provide any guarantee for rows1 == columns2 or rows1 == rows2, etc...
So white all of the limits used are fine -- your compiler cannot guarantee it and warns. However, since you tediously picked though your code to know your limits are good, all it takes is a fraction of a second to confirm it, e.g.
$ valgrind ./bin/read2darrq dat/arr_2-3x3.txt
==29210== Memcheck, a memory error detector
==29210== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==29210== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==29210== Command: ./bin/read2darrq dat/arr_2-3x3.txt
==29210==
90 96 102
216 231 246
342 366 390
==29210==
==29210== HEAP SUMMARY:
==29210== in use at exit: 0 bytes in 0 blocks
==29210== total heap usage: 13 allocs, 13 frees, 732 bytes allocated
==29210==
==29210== All heap blocks were freed -- no leaks are possible
==29210==
==29210== For counts of detected and suppressed errors, rerun with: -v
==29210== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
I've been trying to make an example program using calloc and realloc and I've come across an issue where, when I make an array of integers smaller, it seems to remove the first element instead of the last one.
int *m = (int*)calloc(2, sizeof(int));
*m = 1;
*(m+1) = 2;
printf("\tInt 1: %d\n", m[0]);
printf("\tInt 2: %d\n\n", *(m+1));
// REALLOC
printf("How many elements the array have? ");
scanf("%d", &num);
*m = (int *)realloc(m, num * sizeof(int));
printf("ARRAY NOW HAS %d PLACES\n\n\t", num);
for(i = 0; i < num; i++) {
m[i] = i + 1;
printf("%d ", m[i]);
}
// DELETING MEMBERS OF AN ARRAY
while((d < 0) || (d > num)) {
printf("\n\nChoose which position of the previous array should be deleted (0 = first): ");
scanf("%d", &d);
}
printf("\nUPDATED ARRAY:\n\n");
for(i = d; i < num - 1; i++) {
m[i] = m[i + 1];
}
*m = (int *)realloc(m, (num - 1)*sizeof(int));
num--;
for(i = 0; i < num; i++) {
printf("%d ", m[i]);
}
An example of the program output would be:
Int 1: 1
Int 2: 2
How many elements the array have? 17
ARRAY NOW HAS 17 PLACES
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Choose which position of the previous array should be deleted (0 = first): 6
UPDATED ARRAY:
10620272 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17
And if I include the last member of the array that should have been deleted (in this case m[16]) it shows:
10620272 2 3 4 5 6 8 9 10 11 12 13 14 15 16 17 17
Of course, I'm not entirely sure what's happening but it seems like it's just removing the value of m[0]?
Thanks in advance for any help!
The reason the initial value gets modified is that you are assigning it:
*m = (int *)realloc(m, num * sizeof(int));
should be
m = realloc(m, num * sizeof(int));
Your code should also produce a warning, telling you that an assignment of a pointer to an array element containing ints is invalid. Fixing this warning should have fixed your problem.
Note that an assignment of the form
m = realloc(m, ...);
where m is used on both sides of realloc is inherently unsafe, because realloc could potentially return NULL - for example, when there is not enough memory to allocate. Blind assignment to m would render the old value of m inaccessible, preventing proper deallocation. In production you should assign realloc's result to a temporary, then check it for NULL, and only then assign the result back to m.
In addition to #dasblinkenlight good answer, when reducing the allocation size and the re-allocation fails (a rare event), code can simple continue with the original pointer.
Suggested re-write, assuming num > 0:
// *m = (int *)realloc(m, num * sizeof(int));
void *t = realloc(m, sizeof *m * num);
if (t) {
m = t;
}
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;
}
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)
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.
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;
I'm a beginner and I'm doing some exercises to learn C.
I'm working on dynamic memory allocation with structs and pointers. I have this struct:
struct fact_entry
{ /* Definition of each table entry */
int n;
long long int lli_fact; /* 64-bit integer */
char *str_fact;
};
And this is my main code:
int
main (int argc, char *argv[])
{
int n;
int i;
struct fact_entry *fact_table;
if (argc != 2)
panic ("wrong parameters");
n = atoi (argv[1]);
if (n < 0)
panic ("n too small");
if (n > LIMIT)
panic ("n too big");
/* Your code starts here */
int p;
fact_table = (struct fact_entry *)malloc(n*sizeof(struct fact_entry));
if(fact_table==NULL)
{
fprintf(stderr, "Out of memory, exiting\n");
exit(1);
}
for (i = 0; i<= n; i++)
{
fact_table[i].n = i;
p = i;
fact_table[i].lli_fact=1;
while(p>0)
{
fact_table[i].lli_fact = p * fact_table[i].lli_fact;
p--;
}
p = (int)log10(fact_table[i].lli_fact)+1;
fact_table[i].str_fact = malloc(p);
if(fact_table->str_fact==NULL)
{
fprintf(stderr, "Out of memory, exiting\n");
exit(1);
}
sprintf(fact_table[i].str_fact,"%lld",fact_table[i].lli_fact);
}
/* Your code ends here */
for (i = 0; i <= n; i++)
{
printf ("%d %lld %s\n", fact_table[i].n, fact_table[i].lli_fact,
fact_table[i].str_fact);
}
return 0;
}
The idea is to fill an array of 20 rows. Then every row have 3 columns. In the first column it shows the number of the line "i", in the second, the factorial of the number of the line, in the third the same that in the second but in string format.
I use the log10 to know how long will be the string.
The execution of the program shows this:
0 1 |g�!�2�
1 1 1
2 2 2
3 6 6
4 24 24
5 120 120
6 720 720
7 5040 5040
8 40320 40320
9 362880 362880
10 3628800 3628800
11 39916800 39916800
12 479001600 479001600
13 6227020800 6227020800
14 87178291200 87178291200
15 1307674368000 1307674368000
16 20922789888000 20922789888000
17 355687428096000 355687428096000
18 6402373705728000 6402373705728000
19 121645100408832000 121645100408832000
20 2432902008176640000 2432902008176640000
Line 0 should show 1 in the third column, what happens? It Appears somthing wrong with the malloc.
Thanks!
Not sure that I understand your question.
fact_table = malloc(sizeof(struct fact_entry));
Would only allocate memory for one structure, to have a pointer to a 2d array you'd do
fact_entry **fact_table;
fact_table = malloc(sizeof(struct fact_entry) * RowAmount);
for(int row=0; row < RowAmount; row++)
fact_table[row] = malloc(sizeof(struct fact_entry) * ColAmount);
Now you've allocated memory for a 2d array; every row has columns. And now to access the 2D array you could just do
fact_table[rowIndex][colIndex].myvar
When using Malloc, Realloc, Calloc etc, you've got to keep track of the array size yourself so keep variables for the Rows / Cols. If you want to leave out the columns and only have an array of Rows do the following.
fact_entry *fact_table;
fact_table = malloc(sizeof(struct fact_entry) * RowAmount);
Now you can access the structures by
fact_table[rowIndex].myVar
And don't forget to Free your objects
for(int Row=0; Row < RowAmount; Row++)
free(fact_table[Row]);
free(fact_table);
fact_table = malloc(sizeof(struct fact_entry));
Why? In the first case I'm reserving memory for only one row, true?
Why isn't causing a segmentation fault error?
Correct. But bad code does not imply a crash. You will write on memory that you have not expected to be allocated. But it is your memory! Depending on the implementation malloc might allocate a page size block of memory. This potentially means 4096 bytes. Only if you overwrite this might it crash. Or if you make another allocation which comes from that page might you see problems.
The second, why I can fill in the third column? I can't allocate
memory.. I don't know how I can refer to every row, because I have a
struct with a pointer in a loop... and I don't know how to define the
iterations in the malloc.
Not sure I follow. You can either make a single malloc to allocate all the memory in one go. Then manually loop to fix up the address of str_fact into that block of memory. But that's unnecessarily complicated, although does mean you only have a single alloc. The answer provided by #SuperAgenten Johannes is the correct approach though IMO.