Chciałbym utworzyć losowy ciąg składający się ze znaków alfanumerycznych. Chcę móc określić długość ciągu.
Jak to zrobić w C ++?
Odpowiedź Mehrdada Afshariego wystarczyłaby, ale wydała mi się zbyt rozwlekła, jak na to proste zadanie. Tabele wyszukiwania mogą czasami zdziałać cuda:
void gen_random(char *s, const int len) {
static const char alphanum[] =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < len; ++i) {
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
}
s[len] = 0;
}
s[len] = 0
jest nieprawidłowa. Jeślis
jest łańcuchem C (zakończonym znakiem NULL), to podpis metody nie musiałby zawieraćlen
parametru. Imo, jeśli przekazujesz długość jako argument, zakładasz, że tablica nie jest łańcuchem C. Tak więc, jeśli nie przekazujesz ciągu C do funkcji, linias[len] = 0
może zepsuć rzeczy, ponieważ tablica zmieniłaby się od 0 do len-1. A nawet jeśli przekazujesz ciąg C do funkcji, linias[len] = 0
byłaby zbędna.Oto moja adaptacja odpowiedzi Ates Goral przy użyciu C ++ 11. Dodałem tutaj lambdę, ale zasada jest taka, że możesz ją przekazać i tym samym kontrolować, jakie znaki zawiera twój ciąg:
Oto przykład przekazania lambdy do funkcji losowego ciągu: http://ideone.com/Ya8EKf
Dlaczego miałbyś używać C ++ 11 ?
Na przykład:
Przykładowe dane wyjściowe.
źródło
rand()
w pierwszym fragmencie kodu?rand()
. To nawet nie jest mundur do głośnego płaczu ...Moje rozwiązanie 2p:
źródło
default_random_engine
zamiastmt19937
? Kod wyglądałby bardziej ogólnie.std::default_random_engine
nie jest to coś, co mi się podoba, ponieważ standard nie daje żadnych gwarancji co do jakości, wydajności czy powtarzalności pomiędzy wdrożeniami.sizeof
, zmienićauto&
sięstd::string
, co dajestd::string::length
std::string
byłby prawdopodobnie wolniejszy, ponieważ zawiera wewnętrzny wskaźnik do swoich danych. Oznaczałoby to dodatkowe pośrednictwo, którego nie wymaga tablica statyczna. Równieżsizeof
nigdy nie może być wolniejsze niżstd::string::size
dlatego, że jest stałą czasową kompilacji.std::size
pojawiło się dopiero,C++17
a wciąż jest wiele osób, które tylko kodują,C++11/14
więc zostawię to tak, jak jest na razie.źródło
Właśnie to przetestowałem, działa słodko i nie wymaga tabeli wyszukiwania. rand_alnum () w pewnym sensie wymusza wyświetlanie znaków alfanumerycznych, ale ponieważ wybiera 62 z możliwych 256 znaków, nie jest to wielka sprawa.
źródło
Zamiast ręcznego zapętlania, preferuj użycie odpowiedniego algorytmu C ++ , w tym przypadku
std::generate_n
z odpowiednim generatorem liczb losowych :Jest to zbliżone do czegoś, co nazwałbym „kanonicznym” rozwiązaniem tego problemu.
Niestety, prawidłowe umieszczenie generycznego generatora liczb losowych w C ++ (np. MT19937) jest naprawdę trudne . Dlatego powyższy kod używa szablonu funkcji pomocniczej
random_generator
:Jest to złożone i stosunkowo nieefektywne. Na szczęście jest używany do inicjalizacji
thread_local
zmiennej i dlatego jest wywoływany tylko raz na wątek.Na koniec niezbędne elementy do powyższego to:
Powyższy kod wykorzystuje dedukcję argumentów z szablonu klasy i dlatego wymaga C ++ 17. Można go w prosty sposób dostosować do wcześniejszych wersji, dodając wymagane argumenty szablonu.
źródło
std::size_t
ostd::uniform_int_distribution
? Nie widzę żadnego innego CTADrng
jako domyślnego parametru, z czymś w rodzajutemplate <typename T = std::mt19937> inline thread_local T default_rng = get_random_generator<T>();
std::uniform_int_distribution<>
, co byłoby bezpieczne, ale może ostrzegać o konwersji ze znakiem -> bez znaku.Mam nadzieję, że to komuś pomoże.
Przetestowano na https://www.codechef.com/ide w C ++ 4.9.2
Output: random_str : DNAT1LAmbJYO0GvVo4LGqYpNcyK3eZ6t0IN3dYpHtRfwheSYipoZOf04gK7OwFIwXg2BHsSBMB84rceaTTCtBC0uZ8JWPdVxKXBd
źródło
RandomString(100)
! ;-)std::srand()
tak naprawdę powinno być wywoływane tylko raz na początku programu (najlepiej jako pierwsza rzeczmain()
). Kod w obecnej postaci wygeneruje wiele identycznych „losowych” ciągów, jeśli zostanie wywołany w ciasnej pętli.Oto zabawna jedna linijka. Potrzebuje ASCII.
źródło
źródło
std::string
zamiaststd::string::value_type[]
Coś jeszcze prostszego i bardziej podstawowego, na wypadek gdybyś cieszył się, że twój ciąg zawiera jakiekolwiek drukowalne znaki:
źródło
Losowy ciąg, każdy plik uruchamiania = inny ciąg
źródło
std::generate_n
zakłada, żecustom_string
ma długośćLENGTH_NAME
, ale tak nie jest.Przykład użycia Qt :)
źródło
Sprawmy, aby losowe znów były wygodne!
Stworzyłem ładne rozwiązanie z samym nagłówkiem C ++ 11. Możesz łatwo dodać jeden plik nagłówkowy do swojego projektu, a następnie dodać testy lub użyć losowych ciągów do innych celów.
To krótki opis, ale możesz kliknąć link, aby sprawdzić pełny kod. Główna część rozwiązania znajduje się w klasie Randomer:
Randomer
zawiera wszystkie przypadkowe rzeczy i możesz łatwo dodać do niego własną funkcjonalność. Gdy już to zrobimyRandomer
, bardzo łatwo jest wygenerować ciągi:Napisz poniżej swoje sugestie dotyczące ulepszeń. https://gist.github.com/VjGusev/e6da2cb4d4b0b531c1d009cd1f8904ad
źródło
Jeszcze jedna adaptacja, ponieważ żadna z odpowiedzi nie wystarczyłaby na moje potrzeby. Po pierwsze, jeśli rand () jest używany do generowania liczb losowych, otrzymasz takie same wyniki przy każdym uruchomieniu. Ziarno generatora liczb losowych musi być w pewnym sensie losowe. W C ++ 11 możesz dołączyć bibliotekę „random” i zainicjować ziarno za pomocą random_device i mt19937. To ziarno zostanie dostarczone przez system operacyjny i będzie dla nas wystarczająco losowe (np. Zegar). Możesz podać granice zakresu, które są zawarte [0,25] w moim przypadku. I wreszcie, potrzebowałem tylko losowego ciągu małych liter, więc użyłem dodawania znaków. Z pulą postaci podejście nie wyszło mi.
źródło
źródło
Bądź ostrożny podczas wywoływania funkcji
(zaadaptowane z @Ates Goral ) spowoduje za każdym razem tę samą sekwencję znaków. Posługiwać się
przed wywołaniem funkcji, chociaż funkcja rand () jest zawsze zapełniana wartością 1 @kjfletch .
Na przykład:
źródło
źródło
źródło