Jak zwrócić tablicę z funkcji?

0

Próbuję zwrócić tablicę w funkcji i użyć jej elementu. W Pythonie coś takiego zadziała, w c++ nie działa.

uint32_t funkcja(uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;
    uint32_t wynik[3];

    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    wynik[0] = k;
    wynik[1] = x;
    wynik[2] = w;

    return wynik;
}


int main()
{
    uint32_t k_init = 1; 
    uint32_t x_init = 12345;

    uint32_t k = funkcja(k_init, x_init)[0];

    return 0;
}

Dostaję błąd:

error: invalid conversion from ‘uint32_t*’ {aka ‘unsigned int*’} to ‘uint32_t’ {aka ‘unsigned int’}
-fpermissive]

oraz

error: invalid types ‘uint32_t {aka unsigned int}[int]’ for array subscript

O co chodzi?

3

Zadeklarowany typ zwracany przez funkcję to uint32_t czyli 1 zmienna a nie tablica. W C++ nie da się tak zwrócić tablicy, najlepiej użyj vector.

0

Ok, na elektrodzie wyczytałem, że się da:

https://www.elektroda.pl/rtvforum/topic1083584.html

2
struct kxw { uint32_t k,x,w; } foo()
{
  return kxw { 1,2,3 };
}
3
Tomasz_D napisał(a):

Próbuję zwrócić tablicę w funkcji i użyć jej elementu. W Pythonie coś takiego zadziała, w c++ nie działa.

Po pierwsze, to nie jest C++, a jedziesz prawie niezmienione C.
Mam niedobrą wiaodmosć: C z cała pewnością nie jest takim językiem, że da się cokolwiek postąpić bez dokumentacji.
Język cały stoi na udefined behaviour, czy zamiataniu błędów pod dywan.

Zakładając że po czasie prób i błędów być pokonał błąd kompilacji, prawie na pewno byś wszedł na subtelny błąd wykonania, np zwróciłbyś śmieci

Tomasz_D napisał(a):

Ok, na elektrodzie wyczytałem, że się da:

Elektroda a C/C++ to jest "uczył Marcin Marcina"
To w 95% elektronicy, którzy bardzo chcieli programować, natomiast mają zaświadczenie od lekarza, że nie mogą czytać.

_13th_Dragon napisał(a):
struct kxw { uint32_t k,x,w; } foo()
{
  return kxw { 1,2,3 };
}

Najbardziej prawidłowe podejście w nowoczesnym C, zwrócić strukturę.
W prawdziwym C++ to inna rozmowa.

0

Zacznijmy od tego, że zwracanie dużej porcji danych takich jak tablica przez funkcję jest złym pomysłem, dlatego że wszystko co jest zwracane przez funkcję przechodzi przez stos.

Co prawda w dzisiejszych komputerach można mieć ogromny stos i przepychać przez niego co się chce, jednak jest to bardzo zła praktyka.

W Twoim przypadku tablica jest mała i nie ma powodów do obaw, że coś będzie działać "nieoptymalnie", ale warto mieć dobre nawyki.

Tablice w C czy C++ deklaruje się zazwyczaj na zewnątrz funkcji i przekazuje do funkcji wskaźnik do tablicy na której funkcja ma pracować.

void funkcja(uint32_t * p_wynik[3], uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;
    
    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    p_wynik[0] = k;
    p_wynik[1] = x;
    p_wynik[2] = w;

}


int main()
{
    uint32_t k_init = 1; 
    uint32_t x_init = 12345;
    uint32_t wynik[3];

    funkcja(&wynik, k_init, x_init)[0]; // przekazujemy do funkcji adres tablicy wynik i parametry

    return 0;
}

Jakbym coś pokręcił to tutaj jest dobry, działający przykład:

https://stackoverflow.com/a/11829889/1215291

0

Napisałem coś takiego:


struct kxw { uint32_t k,x,w; }

uint32_t funkcja(uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;

    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    return kxw { k,x,w };
}

int main()
{
    uint32_t k_init = 1; 
    uint32_t x_init = 12345;

    uint32_t k = //jak to wywołać?
    
    return 0;
}

To pewnie nie ma prawa działać, bo tam pewnie trzeba jakoś przypisać elementy tej struktury do zmiennych, nie wiem. Przykłady w Internecie nie sięgają tak daleko, tj. ponad: zdefiniuj strukturę, wywołaj, wypisz.

1

@Tomasz_D: Możesz też tupla użyć:

auto t = std::make_tuple(1,2,3);
4

Mamy 2023 trzeba korzystać z C++11:

std::array<uint32_t, 3> funkcja(uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;
    std::array<uint32_t, 3> wynik;

    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    wynik[0] = k;
    wynik[1] = x;
    wynik[2] = w;

    return wynik;
}

std::array opakowuje C-array, tak że jest wygodniejsze w użyciu (da się zwrócić przez wartość).

Jedna zamiast tablic może lepiej zastosować rozwiązanie od Dragona?

0
MarekR22 napisał(a):

Mamy 2023 trzeba korzystać z C++11:

std::array<uint32_t, 3> funkcja(uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;
    std::array<uint32_t, 3> wynik;

    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    wynik[0] = k;
    wynik[1] = x;
    wynik[2] = w;

    return wynik;
}

std::array opakowuje C-array, tak że jest wygodniejsze w użyciu (da się zwrócić przez wartość).

Jedna zamiast tablic może lepiej zastosować rozwiązanie od Dragona?

To mi działa. Rozwiązania od Dragona nie umiem użyć w moim przykładzie. Wszystko co wiem o strukturach z internetowych poradników, to jak zdefiniować strukturę, wywołać i wypisać.

2

Bo masz: uint32_t funkcja(...
zaś ma być: kxw funkcja(...

#include <iostream>
using namespace std;

struct kxw { uint32_t k,x,w; };

kxw funkcja(uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;

    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    return kxw { k,x,w };
}

int main()
{
    uint32_t k_init = 1; 
    uint32_t x_init = 12345;

    kxw x=funkcja(k_init,x_init);
    
    return 0;
}
0

@MarekR22: można by jeszcze wspomnieć o RVO (Return Value Optimalization):

#include <array>
#include <iostream>

std::array<uint32_t, 3> funkcja(uint32_t k, uint32_t x) {
    uint32_t                s = k | 1;
    uint32_t                w = 0;
    std::array<uint32_t, 3> wynik;

    std::cout << "address of wynik   = " << &wynik << std::endl;

    for (int i = 0; i < 32; i++) {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    wynik[0] = k;
    wynik[1] = x;
    wynik[2] = w;

    return wynik;
}

int main() {
    auto tablica = funkcja(3, 3);
    std::cout << "address of tablica = " << &tablica << std::endl;

    return 0;
}

wynik działania:

address of wynik   = 0xad643ffe04
address of tablica = 0xad643ffe04

widać, że kompilator zastosował RVO i uniknął zbędnego kopiowania obiektu.

1
AnyKtokolwiek napisał(a):
Tomasz_D napisał(a):

Próbuję zwrócić tablicę w funkcji i użyć jej elementu. W Pythonie coś takiego zadziała, w c++ nie działa.

Po pierwsze, to nie jest C++, a jedziesz prawie niezmienione C.

https://4programmers.net/Forum/C_i_C++/364571-suma_elementow_dynamicznej_tablicy_jednowymiarowej?p=1876794#id1876794

Problem ze zwróceniem tablicy w C jest taki, że nie ma tam pełnowartościowej tablicy (obiektu, który ma świadomość swojej liczności, który zna swoje granice, śmiech na sali postawić pytanie: czy pilnuje swoich granic, umie nimi zarządzać)
Jest tylko strasznie prymitywny obszar pamięci - który w pełni można wyrazić jako wskaźnik do pierwszego elementu.

C++ ma prawdziwą tablicę (a nawet dwie) std::array i std:vector

1

Rozwiązanie jest następujące (uwaga - nie działa gdy korzystasz z rekurencji lub wątków):

/* dopisz gwiazdkę po typie zawracanym */
uint32_t* funkcja(uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;
    static uint32_t wynik[3]; /* dopisz kwalifikator "static" */

    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }
    /* normalnie korszystaj z tablicy, pamiętając o inicjalizacji */
    wynik[0] = k;
    wynik[1] = x;
    wynik[2] = w;

    return wynik; /* teraz możesz zwrócić tę tablicę */
}


int main()
{
    uint32_t k_init = 1; 
    uint32_t x_init = 12345;

    uint32_t k = funkcja(k_init, x_init)[0];

    return 0;
}
2
Manna5 napisał(a):

Rozwiązanie jest następujące (uwaga - nie działa gdy korzystasz z rekurencji lub wątków):

No i właśnie z tego powodu to jest złe rozwiązanie.

Mało tego na jednym wątku nie będzie działać prawidłowo, jak dwa razy wywoła się tę funkcję. Np coś takiego:

auto a = funkcja(1, 2);
auto b = funkcja(10, 1);
std::cout << (a[0] + b[0]) << '\n';
0

Zrobiłem tę strukturę:

#include <cstdint>
#include <cstdio>
#include <bitset>
#include <immintrin.h>
#include<iostream>
#include<array>

struct kxw { uint32_t k,x,w; };

struct kxw initializator(uint32_t k, uint32_t x)
{
    uint32_t s = k | 1;
    uint32_t w = 0;

    for (int i = 0; i < 32; i++)
    {
        k += x;
        x = x * k;
        x ^= (w += s);
    }

    return kxw {k,x,w};
}

int main()
{
    uint32_t k_init = 12345; 
    uint32_t x_init = 67891;

    uint32_t k = initializator(k_init, x_init).k;
    uint32_t x = initializator(k_init, x_init).x;
    uint32_t w = initializator(k_init, x_init).w;

    return 0;
}

0
Tomasz_D napisał(a):

Zrobiłem tę strukturę:

    uint32_t k = initializator(k_init, x_init).k;
    uint32_t x = initializator(k_init, x_init).x;
    uint32_t w = initializator(k_init, x_init).w;

Tylko że po chińskiego powtarzasz obliczenia?

    kxw poludzku=initializator(k_init, x_init);
    uint32_t k=poludzku.k;
    uint32_t x=poludzku.x;
    uint32_t w=poludzku.w;
0

Tak a propos, dopiero zauważyłem że to c++ więc czemu podchodzisz do tego od d..py strony?

#include <cstdint>
#include <iostream>
using namespace std;

class kxw
{
	public:
	uint32_t k,x,w;
	kxw(uint32_t k,uint32_t x):k(k),x(x) {}
	kxw &operator++()
	{
	    uint32_t s=k|1;
		w=0;	
	    for(int i=0;i<32;++i)
	    {
	        k+=x;
	        x*=k;
	        x^=(w+=s);
	    }
	    return *this;
	}
};

int main()
{
	kxw it(12345,67891);
	for(int i=0;i<10;++i,++it) cout<<"k="<<it.k<<"; x="<<it.x<<"; w="<<it.w<<";"<<endl;
    return 0;
}
``
0

Dlaczego od d**y strony? Nie wiem czym jest:

kxw(uint32_t k,uint32_t x):k(k),x(x) {}
kxw &operator++()

i

kxw it(12345,67891);

Więc nie mogłem tego tak napisać. Nie idzie tego nawet wygooglać. Generalnie wiem tylko czym są funkcje, nigdy nie używałem klas, ani struktur, kojarzę jedynie z definicji czym są.

1
Tomasz_D napisał(a):

Nie idzie tego nawet wygooglać. Generalnie wiem tylko czym są funkcje, nigdy nie używałem klas, ani struktur, kojarzę jedynie z definicji czym są.

Cóż, to przykre. Jak pracujesz z Rosji może tak być.

Na szczęście u nas google i cały internet działa normalnie

0

Tyle mniej więcej się domyślam z tego:

#include <cstdint>
#include <iostream>
using namespace std;

class kxw // definiujemy klasę
{
	public:
	uint32_t k,x,w;
	kxw(uint32_t k,uint32_t x):k(k),x(x) {} // kolejna klasa o tej samej nazwie w klasie i to pusta? Plus inicjowanie zmiennych w trakcie tworzenia klasy.
	kxw &operator++() // nie wiem co to jest, mniemam, że coś, co wywołuje to co w klamrach raz, a nie można było zdefiniować niepustej klasy i jej wywołać, czy wtedy nie mogłaby zwrócić sama siebie?
	{
	    uint32_t s=k|1;
		w=0;	
	    for(int i=0;i<32;++i)
	    {
	        k+=x;
	        x*=k;
	        x^=(w+=s);
	    }
	    return *this; // zwrócona zostaje klasa kxw?
	}
};

int main()
{
	kxw it(12345,67891); // myślałem, że it to kolejny rodzaj działania na klasę, teraz widzę, że to po prostu sposób wywołania
	for(int i=0;i<10;++i,++it) cout<<"k="<<it.k<<"; x="<<it.x<<"; w="<<it.w<<";"<<endl;
    return 0;
}

0
#include <cstdint>
#include <iostream>
using namespace std;

class kxw // definiujemy klasę
{
	public:
	uint32_t k,x,w;
	kxw(uint32_t k,uint32_t x):k(k),x(x) {} // konstruktor klasy używający listę inicjalizacyjną
	kxw &operator++() // deklaracja oraz definicja przeciążonego operatora `++obj;` gdzie `obj` jest obiektem klasy kxw
	{
	    uint32_t s=k|1;
		w=0;	
	    for(int i=0;i<32;++i)
	    {
	        k+=x;
	        x*=k;
	        x^=(w+=s);
	    }
	    return *this; // zwrócona zostaje referencja do klasy kxw aby można było użyć w naturalny sposób: `x=++y;` gdzie x i y obiekty kxw
	}
};

int main()
{
	kxw it(12345,67891); // użycie konstruktora do stworzenia obiektu "it" typu kxw, podając "k" oraz "x"
	for(int i=0;i<10;++i,++it) cout<<"k="<<it.k<<"; x="<<it.x<<"; w="<<it.w<<";"<<endl; // zwrócić uwagę na ++it w for
    return 0;
}
0

Po co jest konstruktor klasy, skoro mamy zainicjalizowane zmienne k, x, w? To wygląda jak jakaś podwójna inicjalizacja.

Już chyba widzę, jest on potrzebny, żeby później można było go użyć do stworzenia obiektu "it", bo "class kxw" samo w sobie nie przyjmuje żadnych argumentów.

A ten operator właściwie służy do tego, żeby można było wywołać kod poprzez ++it? A nie można w tej klasie umieścić funkcji i wtedy wywoływać ją podobnie jak robiłem to poprzednio, jakoś tak:

kxw init(12345,67891);

uint32_t k = init.k;

Pewnie będzie problem, żeby taka funkcja w klasie zwróciła klasę?

Trochę się trzeba nakombinować w tym c++, żeby zwrócić zwykłą listę zmiennych.

2
Tomasz_D napisał(a):

Po co jest konstruktor klasy, skoro mamy zainicjalizowane zmienne k, x, w? To wygląda jak jakaś podwójna inicjalizacja.

Nawet jeśli jest podwójna, to sobie z tym radzimy. Mamy wyraźnie okreslone priorytety, i co zasłania co.

Już chyba widzę, jest on potrzebny, żeby później można było go użyć do stworzenia obiektu "it", bo "class kxw" samo w sobie nie przyjmuje żadnych argumentów.

To, o czym mówisz, to "niejawna konstrukcja", siłą rzeczy jest bez parametrów
Z wielu powodów konstrutor jest wazny, w prawie zawsze chodzi o zmuszenie do użycia "tak jak zaprojektowałem"

Istnienie choć jednego konstruktora (w tym również bezparametrowego) mocno zmienia sytuację
W C++ może być w sekcji publicznej (dość łatwe intelektualnie), protected (nie można obiektu powołać tak sobie z zewnątrz, autor sygnalizuje: ta klasa przeznaczona do dziedziczenia) czy private

Trochę się trzeba nakombinować w tym c++, żeby zwrócić zwykłą listę zmiennych.

w C++ nie za bardzo jest takie "cuś" jak lista zmiennych, to i zwrócić trudno. Mówisz w koncepcji Pythona prawdopdobnie
Tak, ale języki ściśle kompilowane właśnie tak mają, z tej inwestycji zwrotem jest bezpieczeństwo kompilacji, jak się skompilowało, to najczęściej ma sens, i złączenia nie pękną - (w Pythonie przy niespójności poleci wyjątek na wykonaniu)

Jest najzupełniej prawdą, że w C/C++ napisze się zawsze więcej linii niż w Pythonie, nie dziwi nic

A jak napiszę to jak poprzednio, z użyciem tej struktury, to będzie błąd w sztuce? — Tomasz_D dziś, 11:15

Struct i class w C++ są bardzo podobne, prawie tożsame. Klasa ma defaultowo private, struct public i to jedyna różnica (uwaga, nie przenoś tego na inne jezyki, np C#)

Nie powinieneś się domyślać (absolutnie totalnie nigdy), lecz sięgać po dokumentacje. — _13th_Dragon dziś, 02:34

+1

@Tomasz_D: naprawdę poczytaj coś solidnego a nie zgaduj.

0
Tomasz_D napisał(a):

Trochę się trzeba nakombinować w tym c++, żeby zwrócić zwykłą listę zmiennych.

Dla tego właśnie pokazałem jak tego nie robić, czyli nie zwracamy listę zmiennych.
Jedynie

  1. ustawiamy parametry kxw it(12345,67891);
  2. wywołujemy obliczenia ++it;
  3. pobieramy wyniki it.k,it.x,it.w
  4. ewentualnie wracamy do kroku 2, zauważ że nowe parametry już ustawione.

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