[+] C++ - sortowanie (generowanie) tablicy, b

Potrzebujesz pomocy z C, C++, perl, python, itp.
delpierog
Posty: 24
Rejestracja: 10 lutego 2011, 21:33

[+] C++ - sortowanie (generowanie) tablicy, błąd: Segmentation fault

Post autor: delpierog »

Witajcie
Proszę o pomoc w celu rozwiązania problemu, który zwraca błąd:

Kod: Zaznacz cały

Segmentation fault
Jest to prosty program realizujący generowanie losowo tablicy w celu późniejszego posortowania wybranym algorytmem.

Program działa dobrze do liczb mniejszych niż 33 tysiące, przy większych liczbach dostaję wspomniany błąd.

W założeniu program ma pracować na tablicach do 1.000.000 elementów.

Drugi problem polega na tym iż dostaję ten sam błąd dla małych liczb +/- 1000 w momencie gdy komentarzem ujmę opcję ,,for'' w 57 linijce odpowiadającą za wyświetlanie tablicy po sortowaniu. Jeśli ktoś ma jakiekolwiek uwagi do kodu niech też napisze.

Kod: Zaznacz cały

#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;

    int generuj(int ilosc, int tablica[]);
    int bublesort(int ilosc, int tablica[]);
    int wstawianie(int ilosc, int tablica[]);
    void szybkie(int lewy, int prawy, int tablica[]);
    int kopcowanie(int ilosc, int tablica[]);
    float czas;
    clock_t start,stop;

int main()
{
    int N,tab[N],x;

    cout << "Podaj ilość liczb do wylosowania i posortowania: ";
    cin >> N;
    generuj(N,tab);

    cout << endl << "   WYBIERZ SORTOWANIE: " << endl  << endl << "1.Sortowanie babelkowe" << endl << "2.Sortowanie przez wstawianie" << endl
         << "3.Sortowanie szybkie" << endl << "4.Sortowanie przez kopcowanie"<<endl<< endl <<"Twój wybór to: ";
    cin >> x;
    if(x>5 || x<=0) cout << "PODAJ ODPOWIADAJACA LICZBE Z ZAKRESU <1-4>" << endl;
    else
    {
        switch(x)
        {
            case 1:
                start=clock();
                bublesort(N,tab);
                stop=clock();
                cout << "czas wykonyania sortowania to: " << (stop-start)/(double)CLOCKS_PER_SEC;
                break;
            case 2:
                start=clock();
                wstawianie(N,tab);
                stop=clock();
                cout << "czas wykonyania sortowania to: " << (stop-start)/(double)CLOCKS_PER_SEC;
                break;
            case 3:
                start=clock();
                szybkie(1,N,tab);  // PRZY WYNIKI Z SORTOWANIA DWA PIERWSZE ELEMENTY NIE SA POSORTOWANIE 84 I 0
                stop=clock();
                cout << "czas wykonyania sortowania to: " << (stop-start)/(double)CLOCKS_PER_SEC;
                break;
            case 4:
                start=clock();
                kopcowanie(N,tab); // TAK SAMO JAK WYŻEJ
                stop=clock();
                cout << "czas wykonyania sortowania to: " << (stop-start)/(double)CLOCKS_PER_SEC;
                break;
        }

    for(int i=0; i<N; i++) cout << tab[i]<<endl; //tablica po sortowaniu
    }

return 0;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    int generuj(int ilosc, int tablica[]){
        //cout << "generuj przed forem" << endl;
        for(int i=0; i<ilosc; i++)
        {
            tablica[i]=rand() % 100;
        }

    return 0;
    }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    int bublesort(int ilosc, int tablica[]){

        int p;
        for(int i=ilosc-1; i>0; i--)
        {
            p=1;
            for(int j=0; j<i; j++)
            {
                if(tablica[j]>tablica[j+1])
                {
                    swap(tablica[j],tablica[j+1]);
                    p=0;
                }
            }
         if(p) break;
        }
    return 0;
    }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    int wstawianie(int ilosc,int tablica[])
    {
            int x,i;
           for(int j=ilosc-2; j>=0; j--)
            {
                x=tablica[j];
                i=j+1;
                while( (i<ilosc) && (x>tablica[i]) )
                {
                    tablica[i-1]=tablica[i];
                    i++;
                }

            tablica[i-1]=x;
            }

    return 0;
    }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void szybkie(int lewy, int prawy, int tablica[])
{

  int i,j,piwot;

  i=(lewy+prawy)/2;
  piwot=tablica[i]; tablica[i]=tablica[prawy];
  for(j=i=lewy; i<prawy; i++)
  if(tablica[i] < piwot)
  {
    swap(tablica[i], tablica[j]);
    j++;
  }
  tablica[prawy]=tablica[j]; tablica[j]=piwot;
  if(lewy< (j-1) ) szybkie(lewy, j-1,tablica);
  if( (j+1) <prawy) szybkie(j+1, prawy,tablica);

return ;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int kopcowanie(int ilosc, int tablica[])
{
//Stawiamy kopiec
  int j,k,x,m;
  for(int i=2; i<=ilosc; i++)
  {
    j=i; k=j/2;
    x=tablica[i];
    while( (k > 0) && (tablica[k] < x) )
    {
      tablica[j] = tablica[k];
      j= k; k=j/2;
    }
    tablica[j]=x;
  }

// Rozbieramy kopiec

  for(int i=ilosc; i>1; i--)
  {
    swap(tablica[1], tablica[i]);
    j=1; k=2;
    while(k<i)
    {
      if( (k+1<i) && (tablica[k+1] > tablica[k]) )
        m=k+1;
      else
        m=k;
      if(tablica[m] <= tablica[j]) break;
      swap(tablica[j], tablica[m]);
      j=m; k=j+j;
    }
  }
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
drekkett
Posty: 17
Rejestracja: 24 lipca 2008, 22:01

Post autor: drekkett »

Witaj.
Raczej musisz użyć unsigned integer, gdyż integer przechowuje liczby w zakresie

Kod: Zaznacz cały

−32 768 — +32 767
(ze znakiem).

A bez minusowych wartości:

Kod: Zaznacz cały

0 — +65 535
(bez znaku)
Awatar użytkownika
Rafal_F
Moderator
Posty: 2350
Rejestracja: 29 sierpnia 2008, 16:45

Post autor: Rafal_F »

Na przyszłość w takich przypadkach skompiluj program z parametrem -g, przed uruchomieniem programu wydaj polecenie:

Kod: Zaznacz cały

ulimit -c unlimited
To spowoduje że zostanie utworzony core dump, następnie posłuż się np. tym opisem: http://cs.baylor.edu/~donahoo/tools/gdb/tutorial.html . Generalnie proponuje zapoznać się z jakimś debugerem. W linuksie najpopularniejszy to GDB, do tego jakiś frontend: DDD i można usuwać takie błędy samemu.
delpierog
Posty: 24
Rejestracja: 10 lutego 2011, 21:33

Post autor: delpierog »

drekkett pisze:Witaj.
Raczej musisz użyć...
Zmiana wszystkich typów zmiennych i tablic zmieniona na unsigned int nic nie zmieniła, ale zgodnie z Wikipedią to typ int na 32 bitach ma zakres −2 147 483 648 — +2 147 483 647

Rafal_F, spróbuje na razie jestem na etapie core dumpa, jaki interfejs do gdb mógłbyś polecić?
Awatar użytkownika
Rafal_F
Moderator
Posty: 2350
Rejestracja: 29 sierpnia 2008, 16:45

Post autor: Rafal_F »

Już napisałem DDD: http://www.gnu.org/software/ddd/ jest dostępny w repozytorium Debiana.

Edycja:
Znalazłem problem nie używasz dynamicznej alokacji pamięci. Nie można w ten dynamicznie przydzielać pamięci:

Kod: Zaznacz cały

int N,tab[N],x;
Chodzi o tworzenie tablicy. Sam zapis jest już nielogiczny, bo w momencie w którym wywołujesz tab[N] zmienna N jest jeszcze niezainicjalizowana. I zmienna N ma dziwną wartość. Musisz linijkę:

Kod: Zaznacz cały

int tab[N];
Wywołać po tym jak już zainicjalizujesz N, albo najlepiej skorzystaj z dynamicznej alokacji pamięci tak jak się to powinno robić, po zainicjalizowaniu N:

Kod: Zaznacz cały

int *tab;
tab=new int[N]
I na końcu (przed return 0) trzeba zwolnić pamięć:

Kod: Zaznacz cały

delete []tab;
A tutaj jak to namierzyłem z gdb, bo mi się kodu nie chciało przeglądać:

Kod: Zaznacz cały

rafal@debian:~/Programowanie/sortowanie$ g++ -g ./main.cpp -o prog1
rafal@debian:~/Programowanie/sortowanie$ ./prog1 
Podaj ilość liczb do wylosowania i posortowania: 1000000
Naruszenie ochrony pamięci
rafal@debian:~/Programowanie/sortowanie$ ulimit -c unlimited
rafal@debian:~/Programowanie/sortowanie$ ./prog1 
Podaj ilość liczb do wylosowania i posortowania: 1000000
Naruszenie ochrony pamięci (core dumped)
rafal@debian:~/Programowanie/sortowanie$ gdb ./prog1 core
GNU gdb (GDB) 7.4.1-debian
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/rafal/Programowanie/sortowanie/prog1...done.
[New LWP 3899]

warning: Can't read pathname for load map: Błąd wejścia/wyjścia.
Core was generated by `+     '.
Program terminated with signal 11, Segmentation fault.
#0  0x08048d85 in generuj (ilosc=1000000, tablica=0xbfca84fc) at ./main.cpp:67
67                tablica[i]=rand() % 100;
(gdb) q
Jak widać powyżej program wysypuje się w linijce 67, czyli przy wypełnianiu tablicy losowymi wartościami. A że funkcje:

Kod: Zaznacz cały

generuj(N,tab)
wywołujesz w 4-tej linijce main to znaczy, że problem musi leżeć w gdzieś w 3-ech poprzednich.
delpierog
Posty: 24
Rejestracja: 10 lutego 2011, 21:33

Post autor: delpierog »

Tak jak napisał Rafal_F błąd polegał na alokowaniu pamięci dla tablicy. Po zmianie na tablice dynamiczną problemy znikły. Dziękuję za pomoc. Temat do zamknięcia.
ODPOWIEDZ