Funkcja zwracająca wskaźnik do tablicy, czego to nie działa?

0

Witam, napisałem sobie funkcję, która jako parametr przyjmuje ciąg znaków(string), i zwraca wskaźnik do tablicy int, czyli np. jako parametr podstawie ciąg znaków 1234, to funkcja zwróci wskaźnik do tablicy w której zapisze sie 4,3,2,1 już jako liczby. Funkcja działa poprawnie z jedną tablicą, jeśli dochodzi druga to już jest problem. Nie wiem czy to sprawa błędu w algorytmie funkcji czy coś nie tak ze wskaźnikami? Poniżej dwa kody, pierwszy nie działa, druga działa ale tylko w tym przypadku, kody wyglądają podobnie, różnica jest jedynie w kolejności zapisu liczba2=strtab(string2);

 
#include<iostream>
#include<conio.h>
#include<string>
#include<stdlib.h>
using namespace std;

int* strtab(string a)
{
 int liczby[1000];
 int* wsk;
 wsk=liczby;    
 char buff_ch[1];
 int index=a.length();
 int int_tab[1000];
 int h=0;
 int bufor[1000];
    for(int i=0;i<a.length();i++)
	{
		buff_ch[0]=a[i];
		int_tab[i]=atoi(buff_ch);
	}
   for(int i=index; i>0;i--)
   {
           bufor[i]=int_tab[h];
           h++;
           }
          
           for(int i=0;i<a.length();i++)
	{
		wsk[i]=bufor[i+1];
		}
   return wsk;
}
//------------------------------------------------------------------------

int main()
{
	
	int* liczba1;
	int* liczba2;
	string string1;//lancuch do pierwszej liczby podawanej przez uzytkownika
	string string2;//lancuch do drugiej liczby podawanej przez uzytkownika

	cout<<"Podaj pierwsza liczbe: ";
	cin>>string1;
	cout<<endl;
	cout<<"Podaj druga liczbe: ";
	cin>>string2;
	cout<<endl;
	
	liczba1=strtab(string1);
	liczba2=strtab(string2); // < patrz tu jest różnica międy dwoma kodami!
	
    for(int i=0;i<string1.length();i++)
	{
		cout<<liczba1[i];
	}
	cout<<endl;
	
	for(int i=0;i<string2.length();i++)
	{
		cout<<liczba2[i];
	}
	cout<<endl;
	
	getch();
	return 0;
}

I drugi działający

 
#include<iostream>
#include<conio.h>
#include<string>
#include<stdlib.h>
using namespace std;

int* strtab(string a)
{
 int liczby[1000];
 int* wsk;
 wsk=liczby;    
 char buff_ch[1];
 int index=a.length();
 int int_tab[1000];
 int h=0;
 int bufor[1000];
    for(int i=0;i<a.length();i++)
	{
		buff_ch[0]=a[i];
		int_tab[i]=atoi(buff_ch);
	}
   for(int i=index; i>0;i--)
   {
           bufor[i]=int_tab[h];
           h++;
           }
          
           for(int i=0;i<a.length();i++)
	{
		wsk[i]=bufor[i+1];
		}
   return wsk;
}
//------------------------------------------------------------------------

int main()
{
	
	int* liczba1;
	int* liczba2;
	string string1;//lancuch do pierwszej liczby podawanej przez uzytkownika
	string string2;//lancuch do drugiej liczby podawanej przez uzytkownika

	cout<<"Podaj pierwsza liczbe: ";
	cin>>string1;
	cout<<endl;
	cout<<"Podaj druga liczbe: ";
	cin>>string2;
	cout<<endl;
	
	liczba1=strtab(string1);
	 // < patrz tu jest różnica międy dwoma kodami!
	
    for(int i=0;i<string1.length();i++)
	{
		cout<<liczba1[i];
	}
	cout<<endl;
	liczba2=strtab(string2);
	for(int i=0;i<string2.length();i++)
	{
		cout<<liczba2[i];
	}
	cout<<endl;
	
	getch();
	return 0;
}

0

Dlaczego zwracasz wskaźnik do tablicy ze stosu?

0

Nie wiem bo jeszcze nie doszedłem w procesie swojej nauki do stosu i nie wiem nawet jak wygląda. To jak inaczej mógłbym to zrobić żeby działało?

0

Zwracasz wskaźnik do obszaru pamięci alokowanego na stosie. Ten obszar pamięci jest zwalniany po powrocie z funkcji. Musisz zaalokować pamięć na stercie (podpowiedź: operator new).

0

dorzucę jeszcze jeden bug:
niewłaściwe użycie atoi (podejrzewam, że kolega wcześniej w jakimś Pascalu rzeźbił, który mu jeszcze wszystko zerował na starcie ?)

Wybaczam przekazanie stringa przez wartość ;) (referencje do przećwiczenia)

0

Jeżeli nie chcesz bawić się w ręczne zarządzanie pamięci (wołanie delete[]) to masz dwie możliwości:

#include <iostream>
#include <algorithm>
#include <iterator>
#include <memory>
#include <vector>

std::vector<char> GetDigits_Vector(const std::string& number)
{
	std::vector<char> digits;

	for(int i = 0; i < number.size(); i++)
		digits.push_back(number[i] - '0');

	return digits;
}

std::unique_ptr<char[]> GetDigits_UniquePtr(const std::string& number)
{
	std::unique_ptr<char[]> digits(new char[number.size()]);

	for(int i = 0; i < number.size(); i++)
		digits[i] = number[i] - '0';

	return digits;
}

int main()
{
	std::string number = "1234";

	std::unique_ptr<char[]> digits = GetDigits_UniquePtr(number);
	std::copy(digits.get(), digits.get() + number.size(), std::ostream_iterator<int>(std::cout, " "));
	std::cout << std::endl;

	std::vector<char> digits2 = GetDigits_Vector(number);
	std::copy(digits2.begin(), digits2.end(), std::ostream_iterator<int>(std::cout, " "));
	std::cout << std::endl;

	return 0;
}

Opcja z unique_ptr jest mniej "pamięciożerna", wektor jest dodatkowo kopiowany.

0

Dobra dzięki wielkie, jak znajdę chwilę czasu to przestudiuję to. Pozdrawiam.

1

'stos' to takie bardzo normalne pojecie, ale dla kogoś kto wie co to jest. człowiekowi trzeba to wytłumaczyc. Wyzej w komentarzu masz po krótce a faktycznie wyglada to tak. Jest sobie pewien obszar pamieci nazywany stosem, stos to struktura danych, kolejka filo/lifo (last in, first out/first in, last out), jest to najlepsza struktura do tworzenia danych loalnych wewnatrz funkcji. Kiedy wywołujesz funkcję, zostaje dla niej (dla jej loklanych danych, oraz danych niereferencyjnych z nagłowka/wywołania) przydzielone pewne miejsce, obrabiasz te dane i musisz po ich obrobieniu zwrócic wynik badz przez wartośc zwracaną przez funkcję, bądź przez wskażnik lub referencję, jakkolwiek. Po wyjściu z funkcji obszar który był przydzielonyna jej dane lokalne zostaje 'zwolniony' (niz spólnego z alokacja pamięci). Na przykładzie... Jest 5 elementów. licznik/wskażnik stosu, funkcja 0, którą możesz uznać za np. main(), funkcja A, która potrzbuje 10 bajtów (np. 2 inty i 2 chary) na swoje dane, funkcja B, która potrzebuje 5 bajtów na swoje dane i funkcja C, która potrzbuje 3 bjtów na swoje dane. Funkcja A wywołuje funkcje B, a po wyjsciu z funkcji A wywoływana jest funkcja C. Początkowo wskaznik stosu ma jakąś wartość, czyli funkcja 0, która się aktualnie wykonuje potrzebowała tyle właśnie bajtów na swoje dane lokalne. Następuje z funkcji 0 wywołanie funkcji A, zatem do wskaznika stosu dodawane jst 10 bajtów które potrzbuje funckja A. Z funkcji A wywoływana jest funkcja B, zaten do wskaznika znów dodawane jest kolejne 5 bajtów. Kazda funkcja zna adres swojego obszaru w tym kawałku pamięci. funkcja 0 ma swoich iles bajtów, potem jest obszar funkcji A- 10 bajtów, potem obszar funkcji B, kolejne 5 bajtów. Po wyjsciu z funcji B od wskażnika stosu jest odejmowany rozmiar, który był potrzebny funcji B, na stosi pozostaja ovszary funkcji 0 i A, reszta jest uznana za wolne (i tu jest clue całej sprawy, twojego problemu). po wyjsciu z funkcji A odejmowanych od wskaznika stosu jest 10 bajtów, które były potrzebne funcji A. A potem wywoływana jest funkcja C, która wymaga 3 bajtów i to jest dodawane do wskaźnika stosu.

Zwolnione obszary ne sa czyszczone...

Teraz sobie wyobraż, że funcja C wymaga też 10 bajtów jak funkcja A, jesli będzie miała dokładnie taka sama strukturę danych, to jest w stanie odtworzyć dane funkcji A...

#include <iostream>
#include <string.h>

void B(){
  char b[5]; // 5 bajtow
}

void A(){
  char a[10]; // 10 bajtow
  strcpy(a,"dupa");
  B();
}

void C(){
  char c[10]; // it's not magic
  std::cout << c << "\n";
}

int main(){
  A();
  C();
  return 0;
}

a tak w ogóle to ...

zamiast int liczby[1000]; które są na stosie zrób: int* libczy=new int[1000];
a potem przed getch wpisz delete liczba2;
będziesz miał tablicę dynamiczna alokowana w obszarze sterty, tam gdzie raz zaalokowana pamieć jest zajęta dopóki sam jej nie zwolnisz.

0

Dobra dzięki. Jutro coś pokmimie.

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