简体   繁体   中英

2d dynamic arrays sent to a function in C

The purpose of this code is to see whether a 2d array (matrix) of unknown size (it gets read from a file) has a diagonal which is all the same numbers. If so the function checkdiag should return 1.

the data in the file i`m using is as follows:

3

4 5 6

7 8 9

3 6 7

where the initial 3 represents the size of the matrix, (3x3)

I know for a fact it will run and gather the data from the file as it prints the matrix within the for loop with fscanf. But it will crash every time beyond that. I've tried many way of passing the variable to the function and have done research as to what is going on but I am stumped here.

I am new to coding and 2d array especially.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <conio.h>



int checkdiag(int size, int matrix[][size])
{
    int i,sum=0,verif;
    for(i=0;i<size;i++)
    {
       sum += matrix[i][i];
    }
    if(matrix[0][0]==((double)sum/(double)size))
        verif=1;
    else
        verif=0;


   return (verif);
}

int main()
{
    FILE *filename;
    char inputfile[25];
    int howmany,confirmdiag;
    int i,j; //Counter varibles
    int **matrix; // points to the first cell of 2d array [0][0]


    /* Type in exact file to open */
    printf("Please type in the exact name of the data file you with to use and please make  sure it is within the program folder.\nFor example: \"matrix1.txt\"\n");
    gets(inputfile);
    filename = fopen(inputfile,"r");

    if (filename==NULL)
    {
        system("cls");
        printf("\nCould not find the file you've requested, please make sure the file is on the   same partition.\n\n");
        getch();
        exit(0);
    }

    fscanf(filename,"%d",&howmany); //Scanning file to find size of the matrix

    matrix =(int **) calloc(howmany,sizeof(int*)); //Allocating memory for the ROWS of the matrix which are pointers of size (int*)

    for (i=0; i<howmany; i++)
    {
        matrix[i] =(int *) calloc(howmany,sizeof(int));//Allocating memory for the COLUMNS of the matrix which are integers of size (int)
    }

    for(i=0;i<howmany;i++)
    {
        for(j=0;j<howmany;j++)
        {
          fscanf(filename,"%d",&matrix[i][j]);//Scanning the file to fill the matrix array.
        }
    }

    confirmdiag=checkdiag(howmany, **matrix);

    if (confirmdiag==1)
    {
        printf("The matrix is %dx%d and all the numbers on the main diagonal are the same.",howmany,howmany);
    }
    else if (confirmdiag==0)
    {
        printf("The matrix is %dx%d. All the numbers on the main diagonal are not the same.",howmany,howmany);
    }

    for (i=0; i<howmany; i++)
        free (matrix[i]);

    free(matrix);

    return 0;
}

Looks good. Just a quick reminder: In your function call: **matrix sends only the first element of the matrix matrix(0,0) to the function since you are dereferencing the first entry of the first column. You need to send a pointer to pointer. Try:

confirmdiag=checkdiag(matrix, howmany, howmany);

and for the method definition:

int checkdiag(int** matrix, int sizeCol, int sizeRow)
{
...
}

Good luck!

Change confirmdiag=checkdiag(howmany, **matrix); to confirmdiag=checkdiag(howmany, matrix); as there is no reason to dereference the pointer.

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

int checkdiag(int size, int matrix[][size]){
    int i, v=matrix[0][0];

    for(i=0;i<size;i++){
        if(v != matrix[i][i] || v != matrix[i][size-1-i])
            return 0;
    }

   return 1;
}

int main(void){
    FILE *file;
    char filename[25];

    printf("Please type in the exact name of the data file you with to use and please make sure it is within the program folder.\nFor example: \"matrix1.txt\"\n");
    scanf("%[^\n]%*c", filename);

    if ((file = fopen(filename, "r")) == NULL){
        system("cls");
        printf("Could not find the file you've requested, please make sure the file is on the same partition.\n\n");
        getch();
        exit(EXIT_FAILURE);
    }

    int howmany;
    fscanf(file, "%d", &howmany);

    int (*matrix)[howmany] = malloc(howmany * sizeof(*matrix));

    for(int i=0;i<howmany;i++)
        for(int j=0;j<howmany;j++){
          fscanf(file, "%d", &matrix[i][j]);

    if (checkdiag(howmany, matrix))
        printf("The matrix is %dx%d and all the numbers on the main diagonal are the same.",howmany,howmany);
    else
        printf("The matrix is %dx%d. All the numbers on the main diagonal are not the same.",howmany,howmany);

    free(matrix);

    return 0;
}

While your approach is solid, there are several additional initializations and validations you should make. Your choice of calloc for allocation was excellent. It allocates/initializes the elements to 0 and prevents any attempt to read a value from an uninitialized value. However, you need to check that it succeeded before you go forward in the code.

The same applies to howmany . Before allocating and charging though the code, a simple check that it is a valid number > 0 is needed.

While you free the memory allocated to matrix , you leave yourself open to a memory leak by failing to close file (there will be 500-600 bytes associated with the open file descriptor).

fscanf is fine for reading integer values from a file, but unless you know, and can guarantee, the contents of your input file, using line-input commands like fgets or getline and then parsing the line for the numbers you need is a far more flexible way to get input. That's just something to keep in mind as you go forward. One stray character in your code will cause a matching failure with fscanf . (the return of fscanf should also be checked to insure you completely fill the matrix with valid values -- omitted below)

Lastly, there is nothing wrong with prompting to user to enter a filename, but generally, a block of code should operate on the arguments passed to it. Making use of int argc, char **argv not only eases moving your test code into your main body of code as a function later, etc.. it also prevents having to retype your input over and over during testing :p .

Putting all of that together, and stealing Bluepixy's diagonal check, here is an updated version of your code. Look through it and let me know if you have any questions. ( Note you can add getch and conio.h back as needed, but they should be avoided as they are not portable beyond windows) Also included is a quick print routine to print the matrix to stdout that you may find useful.

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

int checkdiag (int size, int **matrix);
void prn_mtrx (int m, int n, int **matrix);

int main (int argc, char **argv)
{
    if (argc < 2) {
        fprintf (stderr, "error: insufficient input. Usage: %s filename\n", argv[0]);
        return 1;
    }

    FILE *file = NULL;
    char *filename = argv[1];
    int howmany = 0;
    int **matrix = NULL;
    int i = 0;
    int j = 0;

    /* open file & validate */
    if (!(file = fopen (filename, "r"))) {
        fprintf (stderr, "error: file open failed '%s'.\n\n", filename);
        exit (EXIT_FAILURE);
    }

    /* read / validate howmany value */
    if (!fscanf (file, "%d", &howmany) && howmany > 0) {
        fprintf (stderr, "error: invalid howmany value. (size not number > 0)\n\n");
        fclose (file);
        exit (EXIT_FAILURE);
    }

    /* allocate memory for matrix, initialize elements to '0' with calloc */
    if (!(matrix = calloc (howmany, sizeof *matrix))) {
        fprintf (stderr, "error: memory allocation failed '%s'.\n\n", filename);
        exit (EXIT_FAILURE);
    }

    for (i = 0; i < howmany; i++)
        if (!(matrix[i] = calloc (howmany, sizeof **matrix))) {
        fprintf (stderr, "error: memory allocation failed '%s'.\n\n", filename);
        exit (EXIT_FAILURE);
    }

    /* read values from file (preferably with fgets/getline, then parse tokens) */
    for (i = 0; i < howmany; i++)
        for (j = 0; j < howmany; j++)
            fscanf (file, "%d", &matrix[i][j]);

    /* print the matrix */
    printf ("\nThe %dx%d matrix is:\n\n", howmany, howmany);
    prn_mtrx (howmany, howmany, matrix);

    /* check the diagonal */
    if (checkdiag (howmany, matrix))
        printf ("\nThe numbers on the main diagonal are the same.\n\n");
    else
        printf ("\nThe numbers on the main diagonal are NOT the same.\n\n");

    /* close file / free memory allocated to file */
    if (file) fclose (file);

    /* free memory allocated to matrix */
    for (i = 0; i < howmany; i++)
        free (matrix[i]);
    free (matrix);

    return 0;
}

/* check values on matrix diagonal */
int checkdiag (int size, int **matrix)
{
    int i, v = matrix[0][0];

    for (i = 0; i < size; i++) {
        if (v != matrix[i][i] || v != matrix[i][size - 1 - i])
            return 0;
    }

    return 1;
}

/* print a (m x n) matrix (with pad) */
void prn_mtrx (int m, int n, int **matrix)
{
    register int i, j;

    for (i = 0; i < m; i++)
    {
        char *pad = " [ ";
        for (j = 0; j < n; j++)
        {
            printf ("%s%3d", pad, matrix [i][j]);
            pad = ", ";
        }
        printf ("%s", " ]\n");
    }
}

Output

$ ./bin/matrix_diagonal dat/matrix_5.txt

The 5x5 matrix is:

 [   1,   2,   3,   4,   5 ]
 [   6,   7,   8,   9,  10 ]
 [  11,  12,  13,  14,  15 ]
 [  16,  17,  18,  19,  20 ]
 [  21,  22,  23,  24,  25 ]

The numbers on the main diagonal are NOT the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM