Си и двумерные массивы

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by cupper, 7 Sep 2010.

  1. cupper

    cupper Elder - Старейшина

    Joined:
    6 Jun 2007
    Messages:
    369
    Likes Received:
    92
    Reputations:
    5
    было думал подствпомнить Си ну и начал с простеньких задачек. задачка значит: найти n-ое число фибоначчи за log(n). Суть алгоритма не важна. Реализация специально раздутая для того чтобы непосредственно вспомнить как оно работает.
    Я было думал написать эту простенькую программку, потом создать тему а попросить чтобы мне указали что где я делаю неправильно и как сделать лучьше, но...
    Начинался третий день, моя самооценка валяется под столом, руки опущены ниже пола, мечты о работе программистом разбиты в прах.

    Вот код
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    struct sDimension
    {
        int rows;
        int columns;
    };
    
    int matrixPow(int**, const int**, const struct sDimension*, const int);
    int matrixMulti(int**, const struct sDimension*,
                    const int**, const struct sDimension*,
                    const int**, const struct sDimension*);
    int matrixCopy(const int**, const struct sDimension*, int**, const struct sDimension*);
    int** matrixMalloc(const struct sDimension*);
    void matrixFree(int**, const struct sDimension*);
    void matrixDisplay(const int**, const struct sDimension*);
    int fibN(int);
    
    int main()
    {
        int n = 4; // n-ое число Фибоначчи
        printf("F%d = %d", n, fibN(n));
    
        return 0;
    }
    
    int fibN(int n)
    {
        const struct sDimension dimC = {1, 2};
        const struct sDimension dimP = {2, 2};
        int **P = matrixMalloc(&dimP);
        P[0][0] = 0; P[0][1] = 1; P[1][0] = 1; P[1][1] = 1;
        int **Ppow = matrixMalloc(&dimP);
        // matrixFree(Ppow, &dimP);
        matrixPow(Ppow, P, &dimP, n);
        int **C = matrixMalloc(&dimC);
        C[0][0] = 0; C[0][1] = 1;
        int **Fn = matrixMalloc(&dimC);
    
        matrixPow(Ppow, P, &dimP, n);
        //matrixDisplay(Ppow, &dimP);
        matrixMulti(Fn, &dimC, C, &dimC, Ppow, &dimP);
        //matrixDisplay(Fn, &dimC);
        int fib = Fn[0][0];
    
        printf("2---\n");
        matrixFree(Ppow, &dimP);
        matrixFree(Fn, &dimC);
        matrixFree(C, &dimC);
        matrixFree(P, &dimP);
        return fib;
    }
    
    int matrixPow(int **Ppow, const int **P, const struct sDimension *dimP, const int _pow)
    /*
        C[m][n] = A[m][n] ^ pow
        error status:
        0 - good
        1 - pow < 0;
        2 - not a square matrix
    */
    {
        if(_pow < 0)
            return 1;
    
        if(dimP->columns != dimP->rows)
            return 2;
    
        int pow = _pow;
        //Ppow = matrixMalloc(dimP);
    
        matrixCopy(P, dimP, Ppow, dimP);
        --pow;
        int **temp = matrixMalloc(dimP);
        int **localP = matrixMalloc(dimP);
        matrixCopy(P, dimP, localP, dimP);
        while(pow)
        {
            if(pow&1)
            {
                matrixMulti(temp, dimP, Ppow, dimP, localP, dimP);
                matrixCopy(temp, dimP, Ppow, dimP);
                --pow;
            }
            else
            {
                matrixMulti(temp, dimP, localP, dimP, localP, dimP);
                matrixCopy(temp, dimP, localP, dimP);
                pow>>=1;
            }
        }
        matrixFree(localP, dimP);
        matrixFree(temp, dimP);
        return 0;
    }
    
    int matrixMulti(int **C, const struct sDimension* dimC,
                    const int **A, const struct sDimension* dimA,
                    const int **B, const struct sDimension* dimB)
    {
    /*
        A[m][n] * B[p][q] = C[m][q]
        error status:
        0 - good
        1 - matrix's is not co-ordinated
    */
        int Am = dimA->columns, Bq = dimB->rows;
    
        if(Am != Bq || dimC->rows != dimA->rows || dimC->columns != dimB->columns)
            return 1;
    
        int i, j, r;
        for(i=0; i<Am; i++)
        {
            for(j=0; j<Bq; j++)
            {
                C[i][j]=0;
                for(r=0; r<Am; r++)
                    C[i][j] += A[i][r]*B[r][j];
            }
        }
        return 0;
    }
    
    int matrixCopy(const int **from, const struct sDimension *dimFrom,
                    int **to, const struct sDimension *dimTo)
    /*
        copy from -> to
        error status:
        0 - good copy
        1 - dimensions do not match (размерности не совпадают)
    */
    {
        if ((*dimFrom).columns != (*dimTo).columns || (*dimFrom).rows != (*dimTo).rows)
            return 1;
        int i, j;
        for(i = 0; i < dimTo->rows; i++)
            for(j = 0; j < dimTo->columns; j++){
                to[i][j] = from[i][j];
                //printf("IJ = %d:%d\n", i, j);
            }
        return 0;
    }
    
    int** matrixMalloc(const struct sDimension *dim)
    {
        //printf("%d:%d\n", dim->rows, dim->columns);
        int** matrix = (int**)malloc(dim->rows * sizeof(int*));
        int i;
        for(i=0; i<(*dim).rows; i++)
            matrix[i] = (int*)malloc((*dim).columns * sizeof(int));
        return matrix;
    }
    
    void matrixFree(int** matrix, const struct sDimension* dim)
    {
        int i;
        printf("matrixFree rows = %d\n", dim->rows);
        for(i=dim->rows - 1; i>=0; i--)
        {
            //printf("[%d]\n", i);
            //matrixDisplay(matrix, dim);
            free(matrix[i]);
        }
        free(matrix);
    }
    
    void matrixDisplay(const int **matrix, const struct sDimension* dim)
    {
        int i,j;
        //printf("matrixDisplay [%d:%d]\n", dim->rows, dim->columns);
        for(i=0; i<dim->rows; i++)
        {
            for(j=0; j<dim->columns; j++)
            {
                printf("%d \t", matrix[i][j]);
            }
            printf("\n");
        }
        //printf("end matrixDisplay\n");
    }
    
    
    проблемма которую я не могу понять в вызове деструкторов
    в них на функции free() обламывается работа.

    при это если вызвать эту функции деструторы вот тут
    Code:
        int **Ppow = matrixMalloc(&dimP);
        matrixFree(Ppow, &dimP);
        matrixPow(Ppow, P, &dimP, n);
    
    т.е. после создание но перед вызовом любой из функций в которых изменяется значения массива, то все РАБОТАЕТ.
    Я догадываюсь что я тупо не знаю какихто основ Си, но понять каких я не могу. Подскажите в чем может быть проблема ?

    PS. ну и по коду если есть какие замечание высказывайте, нужно больше мнений со стороны (только не по поводу высосаности кода из пальца)
     
    #1 cupper, 7 Sep 2010
    Last edited: 7 Sep 2010
  2. necr0log

    necr0log New Member

    Joined:
    11 Aug 2010
    Messages:
    14
    Likes Received:
    2
    Reputations:
    0
    пздц, ниодного комментария...
    без них разбираться не буду, но крах free() означает, что при использовании памяти, выделенной malloc(), ты вылазишь за ее пределы. Ставим breakpoint, F5 и ползи по коду на пузе.
     
  3. cupper

    cupper Elder - Старейшина

    Joined:
    6 Jun 2007
    Messages:
    369
    Likes Received:
    92
    Reputations:
    5
    да какие комменты, код же банален. Ползал брюхом, не в дебагере а с помощью printf, тоже думал что где то удаляю что то не то, но вставлял распечатку массива перед напосредственно free(), оно сцуко все есть. Притом он два раза отрабатывает нормально для второстепенных массивово в matrixPow, а вот при вызове для Ppow все блин аналогично но сразу же на удалении последней строчки (начинаю с конца) на free падает. Хотя точно таки еже (тоже размерности) второстепенные массивы нормально удаляет.
     
  4. R0nin

    R0nin Member

    Joined:
    11 Jul 2010
    Messages:
    261
    Likes Received:
    24
    Reputations:
    8
    Просто для интереса провел его через gcc, и результат вот такой :
    Code:
    test.c: In function ‘fibN’:
    test.c:36: warning: passing argument 2 of ‘matrixPow’ from incompatible pointer type
    test.c:10: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:41: warning: passing argument 2 of ‘matrixPow’ from incompatible pointer type
    test.c:10: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:43: warning: passing argument 3 of ‘matrixMulti’ from incompatible pointer type
    test.c:11: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:43: warning: passing argument 5 of ‘matrixMulti’ from incompatible pointer type
    test.c:11: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c: In function ‘matrixPow’:
    test.c:82: warning: passing argument 3 of ‘matrixMulti’ from incompatible pointer type
    test.c:11: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:82: warning: passing argument 5 of ‘matrixMulti’ from incompatible pointer type
    test.c:11: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:83: warning: passing argument 1 of ‘matrixCopy’ from incompatible pointer type
    test.c:14: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:88: warning: passing argument 3 of ‘matrixMulti’ from incompatible pointer type
    test.c:11: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:88: warning: passing argument 5 of ‘matrixMulti’ from incompatible pointer type
    test.c:11: note: expected ‘const int **’ but argument is of type ‘int **’
    test.c:89: warning: passing argument 1 of ‘matrixCopy’ from incompatible pointer type
    test.c:14: note: expected ‘const int **’ but argument is of type ‘int **’
    
    короче, гиморой с указателями у тебя мужик, мне пока лень копаться в нем :)
     
    #4 R0nin, 7 Sep 2010
    Last edited: 23 Feb 2012
    1 person likes this.
  5. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    492
    Likes Received:
    187
    Reputations:
    5
    внутри вызова ф-ции
    matrixMulti(Fn, &dimC, C, &dimC, (const int **)Ppow, &dimP);

    срабатывает такой код
    PHP:
    for(i=0i<Ami++)
        {
            for(
    j=0j<Bqj++)
            {
                
    C[i][j]=0;
                for(
    r=0r<Amr++)
                    
    C[i][j] += A[i][r]*B[r][j];
            }
        }
    На втором круге, когда j=1
    тут C[j]=0; ошибка
    чтото с памятью
     
    1 person likes this.
  6. cupper

    cupper Elder - Старейшина

    Joined:
    6 Jun 2007
    Messages:
    369
    Likes Received:
    92
    Reputations:
    5

    однако вы правы, ошибка не там где я предпологал.

    P.S. как всегда, потрачена куча сил и время но поиск ошибки не там где нужно.
    ошибка глупая была, не по тем индексам пробегал матрицы при умножении

    вот так верно
    Code:
    int matrixMulti(int **C, const struct sDimension* dimC,
                    const int **A, const struct sDimension* dimA,
                    const int **B, const struct sDimension* dimB)
    {
    /*
        A[m][n] * B[p][q] = C[m][q]
        error status:
        0 - good
        1 - matrix's is not co-ordinated
    */
        int Am = dimA->columns, Bq = dimB->rows;
    
        if(Am != Bq || dimC->rows != dimA->rows || dimC->columns != dimB->columns)
            return 1;
    
        int i, j, r;
        for(i=0; i<dimA->rows; i++)
        {
            for(j=0; j<dimB->columns; j++)
            {
                C[i][j]=0;
                for(r=0; r<Am; r++)
                    C[i][j] += A[i][r]*B[r][j];
            }
        }
        return 0;
    }
    
    PPS. и чтоб совсем все правильно было
    вместо
    Code:
    int pow = _pow;
    нужно
    Code:
    int pow = _pow - 1;
     
    #6 cupper, 7 Sep 2010
    Last edited: 7 Sep 2010
  7. rudi

    rudi Active Member

    Joined:
    3 Jun 2010
    Messages:
    492
    Likes Received:
    187
    Reputations:
    5
    юзай Visual Studio c++ 6
    ошибки быстро найдешь
    там мощный дебагер