Jak znaleźć i poprawić błąd Segmentation fault?

0

Foster w wątku
Odwracanie macierzy
napisał kod programu odwracającego macierz na podstawie znalezionego u Knutha pomysłu wykorzystującego osiowanie

Próbowałem przełożyć ten kod na C
ale dostaję gdzieś błąd Segmentation fault


#include<stdio.h>
#include<stdlib.h>
#include <math.h>
#define ZERO 1e-7

typedef enum {FALSE,TRUE} boolean;

boolean OdwracanieMacierzy(double** Macierz, unsigned int Stopien)
{
    unsigned int w,k,w1,k1,i;    // Zmienne wykorzystywane przy iteracji
    unsigned int p,q;            // Wspolrzedne elementu osiowego
    unsigned int *c;
    boolean *BylaJuzKolOsiowa;
    double Max;
    double **MacPom;

    MacPom = (double**)malloc(Stopien * sizeof(double*));
    for(i = 0;i < Stopien;i++)
        MacPom[i] = (double*)malloc(Stopien * sizeof(double));

    BylaJuzKolOsiowa = (boolean *)malloc(Stopien * sizeof(boolean));
    c = (unsigned int *)malloc(Stopien * sizeof(unsigned int));

    for(i=0;i<Stopien;i++);
    {
          BylaJuzKolOsiowa[i] = FALSE;
    }
    for(w = 0;w < Stopien;w++)
    {
          c[w] = 0;
          Max = 0.0;
          for(k = 0;k < Stopien;k++)
          {
                if(!BylaJuzKolOsiowa[k])
                if(Max < fabs(Macierz[w][k]))
                {
                       Max = fabs(Macierz[w][k]);
                       p = w;
                       q = k;
                }
          }
          if(Max < ZERO)
          {
                 return FALSE;
          }
          for(w1 = 0;w1 < Stopien;w1++)
             for(k1 = 0;k1 < Stopien;k1++)
                 if(w1 != p && k1 != q)
                     Macierz[w1][k1] -= Macierz[p][k1]*Macierz[w1][q]*1.0/Macierz[p][q];
             for(w1 = 0;w1 < Stopien;w++)
                 if(w1 != p)  Macierz[w1][q] *= (-1.0)/Macierz[p][q];
             for(k1 = 0;k1 < Stopien;k++)
                 if(k1 != q) Macierz[p][k1] *= (-1.0)/Macierz[p][q];
             Macierz[p][q] = 1.0/Macierz[p][q];
             c[w] = q;
             BylaJuzKolOsiowa[q] = TRUE;
          }
    // Permutowanie macierzy
     for(i = 0;i < Stopien;i++)
         for(k = 0;k < Stopien;k++)
              MacPom[i][k] = Macierz[i][k];
     for(k = 0; k < Stopien;k++)
         for(i = 0;i < Stopien;i++)
               Macierz[c[k]][i] = MacPom[k][i];
      for(i = 0;i < Stopien;i++)
         for(k = 0;k < Stopien;k++)
              MacPom[i][k] = Macierz[i][k];
     for(k = 0; k < Stopien;k++)
         for(i = 0;i < Stopien;i++)
               Macierz[i][k] = MacPom[i][c[k]];

     for(i = 0;i < Stopien;i++)
           free(MacPom[i]);
     free(MacPom);

     free(BylaJuzKolOsiowa);
     free(c);

     return TRUE;
}

void Wczytaj(char* path,double** Macierz,unsigned int *Stopien)
{
     FILE *in;
     unsigned int i,j,stopien;
     if((in = fopen(path,"rt")) == NULL)
     {
            fprintf(stderr,"Nie mozna otworzyc pliku do odczytu");
            return;
     }
     fscanf(in,"%d",stopien);
     Macierz = (double **)malloc(stopien*sizeof(double*));
     for(i = 0; i < stopien;i++)
         Macierz[i] = (double *)malloc(stopien * sizeof(double));
     for(i = 0;i < stopien;i++)
         for(j = 0;j < stopien;j++)
               fscanf(in,"%lf",&Macierz[i][j]);
      fclose(in);
     *Stopien = stopien;
}

void Zapisz(char* path,double **Macierz,unsigned int Stopien,boolean OK)
{
     FILE *out;
     unsigned int i,j;
     if((out = fopen(path,"wt")) == NULL)
     {
          fprintf(stderr,"Nie mozna otworzyc pliku do zapisu");
          return;
     }
     if(OK)
     for(i = 0;i < Stopien;i++)
     {
           for(j = 0;j < Stopien;j++)
              fprintf(out,"%lf ",Macierz[i][j]);
           fprintf(out,"\n");
     }
     else
         fprintf(out,"Macierz osobliwa \n");
     fclose(out);
}

int main()
{
   double **Macierz;
   unsigned int Stopien;
   unsigned int i;
   Wczytaj("inverse_matrix_Knuth_in.txt",Macierz,&Stopien);
   if(OdwracanieMacierzy(Macierz,Stopien))
      Zapisz("inverse_matrix_Knuth_out.txt",Macierz,Stopien,TRUE);
   else
      Zapisz("inverse_matrix_Knuth_out.txt",Macierz,Stopien,FALSE);
   for(i = 0;i < Stopien;i++)
       free(Macierz[i]);
   free(Macierz);
   return 0;
}

4

size_t Rozmiar = sizeof(Macierz)/sizeof(Macierz[0]);

To działa tylko dla tablic na stosie, nie zadziała natomiast na tablicy zaalokowanej na stercie przekazanej przez wskaźnik. Obydwa rozmiary musisz przekazać do funkcji jawnie przez argument jeśli chcesz zachować obecny podział na funkcje. Dalej też możesz mieć błędy ale już nie czytałem, najpierw popraw ten fragment.

0

a debugger ci nie wskazuje gdzie sie wysypało?

0

A myślisz że tego nie sprawdzałem. Gdy podmieniłem zmienną Rozmiar na zmienną Stopien przekazywaną przez argument to nadal gdzieś był ten błąd Musi być coś jeszcze
Nie chciało ci cię czytać dalej ? Co do podziału kodu na funkcje to starałem się zachować ten z oryginalnego kodu Fostera

1

A próbowałeś to kompilować z jakimikolwiek warningami ?
Na przykład w wierszu 25 masz nadmiarowy średnik, a w okolicach 46 - ja nie potrafię stwierdzić co ma być wykonywane wewnątrz pętli a co nie...

foo.c:25:5: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation]
   25 |     for(i=0;i<Stopien;i++);

Moje rady:

  1. Czytaj warningi i jeśli ich nie rozumiesz - traktuj je jak błędy. Czasem nawet niewinne "unused variable" może być oznaką poważnego błędu...
  2. NIGDY nie pomijaj nawiasów klamrowych w pętlach i instrukcjach warunkowych
  3. Użyj jakiegoś "sprawdzacza" dostępu do pamięci - np. valgrinda (i/lub odpowiednich opcji dla kompilatora)
  4. Czy aby na pewno poprawnie przekazujesz te wskaźniki ? Jeśli funkcja ma alokować pamięć, to chyba masz jeden poziom za mało...

void foo(int * ptr)
{
  ptr = (int*)malloc(sizeof(int));
}

void bar(int ** ptr)
{
  *ptr = (int*)malloc(sizeof(int));
}

int main()
{
  int * ptr = NULL;
  foo(ptr);
  printf("%p\n", ptr);
  bar(&ptr);
  printf("%p\n", ptr);
  free(ptr);
}

W sumie jeszcze jedna sugestia...
Napisz to w C++ i użyj jakiejś sensownej biblioteki do obsługi macierzy - ja używam Armadillo, ale jest wiele innych do wyboru (np. Eigen, Blaze, Fastor...)

0

Bartek
Co do kodu w okolicach linijki 46 to dawałem klamerki tam gdzie był blok begin end
Sprawdzałem te ostrzeżenia ,usunąłem średnik , dopisałem operator & do fscanf
i zostało mi ostrzeżenie
F:\Work_C\projects\OdwracanieMacierzyKnuth\main.c|129|warning: 'Macierz' is used uninitialized in this function [-Wuninitialized]|
Nie zainicjalizował zmiennej Macierz ?
To może być ta linijka
Chciałbym zachować oryginalny podział kodu na funkcje
Jak poprawić kod aby tego ostrzeżenia nie pokazywało

0

Pisz zmienne po angielsku Skoro masz błąd na swojej funkcji wczytującej to chyba wypadało by ZAKOŃCZYĆ program.
Return; na funkcji void tego nie robi.

2

Nie chciało ci cię czytać dalej ?

No nie chciało. Masz dość podstawowy błąd na samym początku wiec dlaczego miałbym czytać dalej? Nie znam całej historii edycji tego kodu patrząc tylko na jego stan obecny, przeceniasz moje możliwości. Jeżeli chciałbyś żeby ktoś bardziej zaangażował się w Twój problem to musiałbyś dać coś więcej od siebie. Np. pokazać logi jak daleko zachodzi program przed segfaultem, albo pokazać kod, który można by łatwo odpalić np. z wandbox.org. Bez tego, niestety, jesteś skazany na dość płytkie odpowiedzi, którym ciężko się dziwić gdy widzi się masę słabej jakości kodu bez widocznej woli autora by ułatwić odpowiadającym sprawę.

0

Funkcja Wczytaj nie działa tak jak powinna skoro zmienna Macierz nie zostaje zainicjalizowana

To jest dobre, konkretne pytanie. Z tego co widzę, to inicjalizowana jest chyba poprawnie, ale niepoprawnie ją zwracasz. Jeżeli chcesz zwrócić dwuwymiarową tablicę (macierz) poza funkcję, to musisz to zrobić poprzez wskaźnik. W tej chwili, inicjalizujesz macierz do kopi w argumencie.

Powinno to wyglądać jakoś tak

void Wczytaj(char* path,double*** Macierz,unsigned int *Stopien)
{
   double **matrixPtr = *Macierz;
   // ......
}


int main()
{
   double **Macierz;

   //.....
   
   Wczytaj("", &Macierz, &Stopien);
}

1
nowy121105 napisał(a):
#define ZERO 1e-7

:D

0

Wkleiłem następujący kod do wandboxa

#include<stdio.h>
#include<stdlib.h>
#include <math.h>
#define ZERO 1e-7

typedef enum {FALSE,TRUE} boolean;

boolean OdwracanieMacierzy(double** Macierz, unsigned int Stopien)
{
    unsigned int w,k,w1,k1,i;    // Zmienne wykorzystywane przy iteracji
    unsigned int p,q;            // Wspolrzedne elementu osiowego
    unsigned int *c;
    boolean *BylaJuzKolOsiowa;
    double Max;
    double **MacPom;
    //size_t Stopien = sizeof(Macierz)/sizeof(Macierz[0]);

    MacPom = (double**)malloc(Stopien * sizeof(double*));
    for(i = 0;i < Stopien;i++)
        MacPom[i] = (double*)malloc(Stopien * sizeof(double));

    BylaJuzKolOsiowa = (boolean *)malloc(Stopien * sizeof(boolean));
    c = (unsigned int *)malloc(Stopien * sizeof(unsigned int));

    for(i=0;i<Stopien;i++)
    {
          BylaJuzKolOsiowa[i] = FALSE;
    }
    for(w = 0;w < Stopien;w++)
    {
          c[w] = 0;
          Max = 0.0;
          for(k = 0;k < Stopien;k++)
          {
                if(!BylaJuzKolOsiowa[k])
                if(Max < fabs(Macierz[w][k]))
                {
                       Max = fabs(Macierz[w][k]);
                       p = w;
                       q = k;
                }
          }
          if(Max < ZERO)
          {
                 return FALSE;
          }
          for(w1 = 0;w1 < Stopien;w1++)
             for(k1 = 0;k1 < Stopien;k1++)
                 if(w1 != p && k1 != q)
                     Macierz[w1][k1] -= Macierz[p][k1]*Macierz[w1][q]*1.0/Macierz[p][q];
             for(w1 = 0;w1 < Stopien;w1++)
                 if(w1 != p)  Macierz[w1][q] *= (-1.0)/Macierz[p][q];
             for(k1 = 0;k1 < Stopien;k1++)
                 if(k1 != q) Macierz[p][k1] *= (1.0)/Macierz[p][q];
             Macierz[p][q] = 1.0/Macierz[p][q];
             c[w] = q;
             BylaJuzKolOsiowa[q] = TRUE;
          }
    // Permutowanie macierzy
     for(i = 0;i < Stopien;i++)
         for(k = 0;k < Stopien;k++)
              MacPom[i][k] = Macierz[i][k];
     for(k = 0; k < Stopien;k++)
         for(i = 0;i < Stopien;i++)
               Macierz[c[k]][i] = MacPom[k][i];
      for(i = 0;i < Stopien;i++)
         for(k = 0;k < Stopien;k++)
              MacPom[i][k] = Macierz[i][k];
     for(k = 0; k < Stopien;k++)
         for(i = 0;i < Stopien;i++)
               Macierz[i][k] = MacPom[i][c[k]];

     for(i = 0;i < Stopien;i++)
           free(MacPom[i]);
     free(MacPom);

     free(BylaJuzKolOsiowa);
     free(c);

     return TRUE;
}

double ** Wczytaj(unsigned int *Stopien)
{
    unsigned int i,j,stopien;
    double **Macierz;
    scanf("%d",&stopien);
     Macierz = (double **)malloc(stopien*sizeof(double*));
     for(i = 0; i < stopien;i++)
         Macierz[i] = (double *)malloc(stopien * sizeof(double));
     for(i = 0;i < stopien;i++)
         for(j = 0;j < stopien;j++)
               scanf("%lf",&Macierz[i][j]);
     *Stopien = stopien;
     return Macierz;
}

void Zapisz(double **Macierz,unsigned int Stopien,boolean OK)
{
     unsigned int i,j;
     if(OK)
     for(i = 0;i < Stopien;i++)
     {
           for(j = 0;j < Stopien;j++)
              printf("%lf ",Macierz[i][j]);
           printf("\n");
     }
     else
         printf("Macierz osobliwa \n");
}


/*
double** Wczytaj(char* path,unsigned int *Stopien)
{
     FILE *in;
     unsigned int i,j,stopien;
     double **Macierz;
     if((in = fopen(path,"rt")) == NULL)
     {
            fprintf(stderr,"Nie mozna otworzyc pliku do odczytu");
            return NULL;
     }
     fscanf(in,"%d",&stopien);
     Macierz = (double **)malloc(stopien*sizeof(double*));
     for(i = 0; i < stopien;i++)
         Macierz[i] = (double *)malloc(stopien * sizeof(double));
     for(i = 0;i < stopien;i++)
         for(j = 0;j < stopien;j++)
               fscanf(in,"%lf",&Macierz[i][j]);
      fclose(in);
     *Stopien = stopien;
     return Macierz;
}

void Zapisz(char* path,double **Macierz,unsigned int Stopien,boolean OK)
{
     FILE *out;
     unsigned int i,j;
     if((out = fopen(path,"wt")) == NULL)
     {
          fprintf(stderr,"Nie mozna otworzyc pliku do zapisu");
          return;
     }
     if(OK)
     for(i = 0;i < Stopien;i++)
     {
           for(j = 0;j < Stopien;j++)
              fprintf(out,"%lf ",Macierz[i][j]);
           fprintf(out,"\n");
     }
     else
         fprintf(out,"Macierz osobliwa \n");
     fclose(out);
}

*/

int main()
{
   double **Macierz;
   unsigned int Stopien;
   unsigned int i;
   //Macierz = Wczytaj("inverse_matrix_Knuth_in.txt",&Stopien);
   Macierz = Wczytaj(&Stopien);
   if(OdwracanieMacierzy(Macierz,Stopien))
      //Zapisz("inverse_matrix_Knuth_out.txt",Macierz,Stopien,TRUE);
      Zapisz(Macierz,Stopien,TRUE);
   else
      //Zapisz("inverse_matrix_Knuth_out.txt",Macierz,Stopien,FALSE);
   for(i = 0;i < Stopien;i++)
       free(Macierz[i]);
   free(Macierz);
   return 0;
}


Chłopaki wandbox pomógł mi znaleźć literówki i program działa choć nie wypisuje tego co powinien
Ponadto wandbox wypisał mi dwa ostrzeżenia w których nie bardzo wiem o co chodzi
Literówki były w miejscu gdzie inkrementowałem zmienną sterującą iteracją
Teraz muszę sprawdzić czy to ja źle przepisałem kod Fostera
czy to Foster źle zapisał algorytm który podpatrzył u Knutha bo nie wypisuje mi macierzy odwrotnej
Wpis Bartka był też pomocny
Wpis tego co wstydzi się swojego imienia dopiero wtedy gdy wskazałem miejsce w którym może być błąd

W sumie mnie do tego czym się ostatnio bawiłem bardziej by się przydał jakiś efektywny algorytm nie wykorzystujący dzielenia
I chyba lepiej w takim razie byłoby zmodyfikował eliminację Gaussa-Jordana bo metoda wykorzystująca twierdzenie Cayleya-Hamiltona nie jest zbyt efektywna

0
Bartłomiej Golenko napisał(a):

A próbowałeś to kompilować z jakimikolwiek warningami ?
Na przykład w wierszu 25 masz nadmiarowy średnik, a w okolicach 46 - ja nie potrafię stwierdzić co ma być wykonywane wewnątrz pętli a co nie...

foo.c:25:5: warning: this ‘for’ clause does not guard... [-Wmisleading-indentation]
   25 |     for(i=0;i<Stopien;i++);

Moje rady:

  1. Czytaj warningi i jeśli ich nie rozumiesz - traktuj je jak błędy. Czasem nawet niewinne "unused variable" może być oznaką poważnego błędu...
  2. NIGDY nie pomijaj nawiasów klamrowych w pętlach i instrukcjach warunkowych
  3. Użyj jakiegoś "sprawdzacza" dostępu do pamięci - np. valgrinda (i/lub odpowiednich opcji dla kompilatora)
  4. Czy aby na pewno poprawnie przekazujesz te wskaźniki ? Jeśli funkcja ma alokować pamięć, to chyba masz jeden poziom za mało...
  1. Używaj programu do formatowania kodu, np. clang-format, etc.
    for(i=0;i<Stopien;i++);
    {
          BylaJuzKolOsiowa[i] = FALSE;
    }

jak wcześniej wspomniano powyższy kod ma znak ; na końcu linii, który po formatowaniu jest uwydatniony i łatwiej taki błąd zauważyć:

    for (i = 0; i < Stopien; i++)
        ;
    { BylaJuzKolOsiowa[i] = FALSE; }

1 użytkowników online, w tym zalogowanych: 0, gości: 1