Anomalie funkcji scanf()

0

Witam!
Mam pytanie odnośnie 2 anomali funkci scanf() z którymi przez jakiś czas nie mogłem sobie poradzić i dalej nie moge ale znalazłem inne wyjście:

  1. Problem polega na tym że jak zrobie cos takiego:
#include <iostream>
#include <string>
using namespace std;
string s;
int main(){
    scanf("%s", s.c_str());
    printf("Zawartosc ciagu:\n%s\nDlugosc ciagu:\n%d\n", s.c_str(), s.size());
    return 0;
}

to jak bym wpisywał teksty o różnych wielkościach to zmienna s zawsze będzie zawierać to co trzeba a metoda size() zawsze będzie zwracać 0, dlaczego 0, a nie faktyczną długość ciągu??

  1. Kolejną sprawa jest taka:
#include <iostream> 
long long int a, b;
char c; 
int main(){ 
   scanf("%d %d %c", &a, &b, &c); 
   printf("' %d ' ' %d ' ' %c '", a, b, c); 
   system("pause");
   return 0; 
}

Wejście:

123 123 A

Wyjście:

‘ 123 ‘ ‘ 0 ‘ ‘ { ‘

#include <iostream> 
long int a, b;
char c; 
int main(){ 
   scanf("%d %d %c", &a, &b, &c); 
   printf("' %d ' ' %d ' ' %c '", a, b, c); 
   system("pause");
   return 0; 
}

Wejście:

123 123 A

Wyjście:

‘ 123 ‘ ‘ 123 ‘ ‘ A ‘

Przecież te kody różnią się tylko jednym long wiec dlaczego gdy jest long long nie chce pobrać funkcja danych prawidłowo??

0

bo NIE WOLNO tak stosować stringa!

Wyraźnie masz napisany prototyp metody c_str:

const char* c_str ( ) const;

czyli zwraca ciąg STAŁYCH znaków.

Jak już używasz C++ i biblioteki STL (string) to czemu nie użyjesz strumieni.

cin >> s;

Swoją drogą dawno nie widziałem takiego kwiatka.

0

Dziękuję za odpowiedź
To znaczy że nie ma możliwości pobrania stringa przez scanf?? Nie wiem dlaczego, ale lepiej mi się działa na printf/scanf niż na strumieniach. (Ciągle czekam na odpowiedź na 2 pytanie)

0

poprawiasz swojego posta i chcesz żebym się cofnął w czasie i udzielił ci odpowiedzi?
String formatujący musi dokładnie opisywać typ danych zapisywanych/odczytywanych, jeśli są jakieś rozbieżności (zwłaszcza jeśli chodzi o rozmiar danych) to różne dziwne rzeczy mogą się zdarzyć. To jest duża wada printf i scanf. Najprostsze rozwiązanie to stosować strumienie. Inne to czytać dokumentacje do printf i scanf i poprawić string formatujący (dodać "l" po "%" jeśli dobrze pamiętam).

0

Źle pamiętasz to nic nie daje. Niestety. Ale i tak bardzo dziękuję za odpowiedź i dobre chęci :)

0

chyba jednak dobrze pamiętam: patrz tu.
Niestety nie ma tam nic na temat podwójnych long.
Z pojedynczym long mogło ci działać bez "l" bo w niektórych kompilatorach nie ma różnicy pomiędzy "long int" i "int".

0

dla podwójnych jest %lld.

0

Nie wprowadzaj w błąd, albo najpierw sprawdź winerfresh. Ja używam g++ więc u mnie tak jak marekR22 napisał "l" nic nie daje bo long int i int są tak samo traktowane. A co do tych stringów to nie da się pobrać na pewno stringa przez scanf?

0

Nie, bo w C stringa nie było.

0
p2004a napisał(a)

Nie wprowadzaj w błąd, albo najpierw sprawdź winerfresh. Ja używam g++ więc u mnie tak jak marekR22 napisał "l" nic nie daje bo long int i int są tak samo traktowane.

[rotfl]
Szczyt hipokryzji - zarzucić komuś, że nie sprawdził czy jego porada działa, podczas gdy się samemu tego nie zrobiło.

$ cat test.c
#include <stdio.h>
long long int a, b;
char c;
int main(){
   scanf("%lld %lld %c", &a, &b, &c);
   printf("' %lld ' ' %lld ' ' %c '", a, b, c);
   return 0;
}
$ g++ test.c
$ echo '123 123 A' | ./a.out
' 123 ' ' 123 ' ' A '
$ cat test.c
#include <stdio.h>
long long int a, b;
char c;
int main(){
   scanf("%d %d %c", &a, &b, &c);
   printf("' %d ' ' %d ' ' %c '", a, b, c);
   return 0;
}
$ g++ test.c
$ echo '123 123 A' | ./a.out
' 123 ' ' 0 ' ' { '

Ja widzę różnice

0

Dzieci drogie, scanf z C99 obsługuje 'll', ten z C++ nie...

0

A co do tych stringów to nie da się pobrać na pewno stringa przez scanf?

Da się , ale nikt rozsądny tego nie robi ....
patrz ->MarekR22 02-04-2009 08:47 - pierwsza odpowiedz .

Do stringa :
http://www.cplusplus.com/reference/string/getline.html

0

Ucho nie działa spraedzałem i kopiowałem też twój kod i nie działa dzejo wszystko fajnie tylko getline() to nie scanf() acha mi zalerzy na scanf a nie na strumieniach.

0

Nie morduj tematu , można wpisać scanf-em do string ale po przydzieleniu
odpowiedniego buf w string .
Jeśli zadeklarujesz string w postaci "string zmienna" to prawdopodobnie w trakcie
"pisania" przekroczysz rozmiar bufora znakowego w string który jest na razie pusty.

W ten sposób nie używa się obiektu string bo jest to bez sensu .
Pisz do tablicy C i potem przypisz dane do string , bo to co próbujesz wykonać
jest niepoprawne i niebezpieczne,,,
czyli to :

    string a ;
    a.resize(20);
    scanf("%19s",a.c_str());
    cout << a << endl ;

Pozostaje jeszcze problem spacji :
http://forum.programuj.com/viewtopic.php?p=28461&highlight=#28461

0

@p2004a sprawdzałem czy działa, bo kiedyś potrzebowałem. Więc mi tu nie bądź hipokrytą jak powiedział @ucho.

zuo napisał(a)

Dzieci drogie, scanf z C99 obsługuje 'll', ten z C++ nie...

To już jest komedia. Jak niby miało by nie obsługiwać tego C++ skoro long longi zostały dla niego stworzone?? C99 je tylko "pożyczyło". A tak ogółem to funkcja scanf() w C++ i C to jest ta sama funkcja.

PS
Też używam G++

0
winerfresh napisał(a)
zuo napisał(a)

Dzieci drogie, scanf z C99 obsługuje 'll', ten z C++ nie...

To już jest komedia. Jak niby miało by nie obsługiwać tego C++ skoro long longi zostały dla niego stworzone?? C99 je tylko "pożyczyło". A tak ogółem to funkcja scanf() w C++ i C to jest ta sama funkcja.

Sam jesteś komedia, ale z jednym masz rację - scanf w C++ i ANSI C to ta sama funkcja. Jak napisałem - ll to 'nowa' sprawa, klamoty C w C++ pochodzą ze starszej rewizji standardu. ISO 14882-2003 implementuje klamoty z ISO 9899-1990, a ten wsparcia dla long long nie posiada. Dziecko, wróć do książek.

0

A który kompilator się tego trzyma??

0
winerfresh napisał(a)

A który kompilator się tego trzyma??

Intel, Comeau, CL z Visuala to zależnie od wersji biblioteki, G++ na Windows.. Stare Borlandy chyba też, od lat tego ścierwa nie używam więc trudno oceniać.

Zamiast bronić się w absurdalny sposób to przyznaj się do błędu - jeżeli już jest to wspierane to przez rozszerzenia, do obsługi nowych rzeczy są dedykowane dla C++ strumienie.

0
dzejo napisał(a)

Nie morduj tematu , można wpisać scanf-em do string ale po przydzieleniu
odpowiedniego buf w string .

    string a ;
    a.resize(20);
    scanf("%19s",a.c_str());
    cout << a << endl ;

wiesz co, nie posadzalbym Cie dotad o taka zenade..

nigdy tego przenigdy *rwa nie rób. po to c_str zwraca cholerne CONST, bys tego sie lamac nie odwazyl. string nie daje zadnej gwarancji, ze to co ma w srodku, jest ciagle i uzywalne do zapisu. to, ze jak mu zrobisz resize i poprosisz o c_str - oczywiscie, znaczy sie ze c_str faktycznie musi zwrocic conajmniej char[21]. nie znaczy to jednak, ze string nie ma prawa np. w ciemno co kazdy c_str alokowac sobie nowej przestrzeni a poprzednia stara wywalac. przeciez to jego bufor i zwracany constem, nie do zmiany przez szarakow.. a i tez przeciez zrobiles mu resize na swiezym pustym stringu? skad wiesz, ze implementacja stringa nie jest zoptymalizowana i w takim konkretnym przypadku nie zapamietuje sobie "jedem pusty, chcieli resize" i nie trzyma nic fizycznie az do żądania tresci ktore sobie moze wprost wygenerowac tablice "size" razy 0x00 na biezaco?

oczywiste jest, ze string tego nie robi w ten sposob, bo komu by sie chcialo. ale pokazuje to ze jest cos takiego jak dokumentacja i zalozenia. to ze ten kod dzial u Ciebie na Twoim kompilatorze, nie znaczy ze jest poprawny. nie znaczy ze bedze dzialal na innym kompilatorze, ani nawet nie znaczy ze bedzie dzialac na tym samym kompilatorze za dwa lata na nowszej wersji.

string ma c_str i data jako const, poniewaz dopuszczone zostalo, aby implementacja trzymala sobie tresc w formie nieciaglej (np. lista kolejnych kawalkow zamiast jednej duzej tablicy -- pomysl o wstawianiu/kasowaniu czegos ze srodka dlugiego napisu..) i zeby sklecala to w formie ciaglej dopiero na wywolaniu c_str/data. jesli tak to implementer napisze, co by sie stalo wtedy, gdybys zrobil:

string zuo = "ala ma ";
zuo += "_____";
zuo += " kotkow";
scanf("%s", zuo.c_str() + 7);
cout << zuo << endl;
zuo[0]='u';
cout << zuo <<endl;

?
ano, moze zobaczylbys poprawny napis "ala ma wpitu kotkow" za pierwszym coutem, ale za drugim razem moze zobaczylbys "ula ma _____ kontow", poniewaz string wykrylby zmiane i zregenerowalby tekst na podstawie wewnetrznie trzymanych kawalkow, ktorych Ty nigdy przy normalnej pracy bys nie zauwazyl..
a czemu te kawalki by sie nie odswiezyly po scanf'ie? string nie ma mozliwosci wykrycia zmian w buforze po ruszeniu ich na chama przez c_str!! przeciez to zwraca char* na ktorym string nie ma absolutnie zadnej mozliwosci kontroli/feedbacku.. musialby za kazda operacja nastepujaca po c_str liczyc i sprawdzac sumykontrolne/hashe/etc.. to dopiero byloby ciezkie i czasozerne..

zreszta, kurde, na chlopski rozum, po jaka cholere bylo tworzyc osobna klase string do trzymania ciagow znakow?
a czemu nie wrzucili se te metody do vector i uzywac vector<char> skoro to wszystko by mialo byc tylko opakowaniem na tablice charow!

string i vector sie RÓŻNIĄ.
string moze być nieciagly i robic magie, moze, BA. prawie na pewno ma mechanizm copy-on-write *). vector jest ciagly i kopiuje zawsze z wartosciami.
dlatego c_str i data maja cholerne CONST, dlatego vector nigdzie w analogicznych nie ma const.

*) - kolejny przyklad: ciekawe czy Twoj kompilator ma copy-on-write w stringu.. sprobuj tego, albo sie domysl po prostu..:

string zuo = "ala ma _____ kotkow";
string druga = zuo;
string trzecia = zuo;
scanf("%s", zuo.c_str() + 7);
cout << zuo << endl;
cout << druga << endl;
cout << trzecia << endl;

jedynym sposobem na prawidlowe pobranie do stringa jakiegos tekstu przez scanf jest - dostarczenie scanfowi CIĄGLEGO bufora nad ktorym masz 100% kontrole i potem przepisanie jego zawartosci do stringa, w najtrywialniejszej postaci:

vector<char> bufor(100, '\0');  //zakladajac ze nikomu nigdy nie uda sie wpisac \x00
scanf("%s", &bufor.front()); //a tu przydaloby sie pomyslec o ograniczeniu dlugosci pola %s do 100..
string niezuo(bufor.begin(), find(bufor.begin(), bufor.end(), '\0')); //<-- gwozdz programu..
0

(..winni się tłumaczą , zdaje się że niezbyt jasno opisałem o co mi chodzi ..
moim zamiarem było przedstawienie kodu którego nie należy używać, napisałem że "się da" bo
może to zadziałać i robić złudne wrażenie że wszystko jest Ok .)
quetzalcoatl :

nie posadzalbym Cie dotad o taka zenade..

i bardzo słusznie ,ten kod jest do d..y [chwilowo działa ale może nadejść dzień kiedy przestanie :-D ]
Prawdopodobnie implementacja biblioteki której używam ze string jest taka że się
natychmiast to nie posypało .
Nie mam zamiaru sprawdzać bo:
NIGDY bym czegoś takiego nie zastosował w swoim programie .
Podałem tylko przykład co gość chce zrobić (i bardzo mu na tym zależy) a jak chce sobie spaprać program to jego sprawa .
dzejo napisało:

Pisz do tablicy C i potem przypisz dane do string , bo to co próbujesz wykonać
jest niepoprawne i niebezpieczne,,,
czyli to :
string a ;
a.resize(20);
scanf("%19s",a.c_str());
cout << a << endl ;

Fakt że nie napisałem dokładnie dlaczego nie - ale to pytanie nie padło ze strony
autora tematu a powinno ,,,
A dlaczego nie? - właśnie z tego powodu -

quetzalcoatl:
string i vector sie RÓŻNIĄ.
string moze być nieciagly i robic magie, moze, BA. prawie na pewno ma mechanizm copy-on-write *). vector jest ciagly i kopiuje zawsze z wartosciami.
dlatego c_str i data maja cholerne CONST, dlatego vector nigdzie w analogicznych nie ma const.

Nikt nie zabrania mysleć , sprawdzić - zastanowić się :-)
i wdepnąć w następne bagno ... bo to co wydaje się oczywiste teoretycznie
w praktyce już może takie nie być ...

Ja na przykład używam kompilatora który daje takie "kwiatki" :
http://4programmers.net/Forum/391404?h=#id391404
mimo wszystko lubię go
i bądz tu zdrowy ....

0

serdeczne dzieki quetzalcoatl za wytłumaczenie :) ja nie jestem jeszcze w te klocki dobry więc wybaczcie mi te pytania.

0

dzejo -

rotfl..

z tego co pamietam, chwycilem za klawiature w chwili przeczytania "Pisz do tablicy C i potem przypisz dane do string" i zobaczenia katem oka dalszego kodu:)
..do "bo to co próbujesz wykonać jest niepoprawne i niebezpieczne,,," najwyrazniej juz nie dotarlem :)

cofam tę 'zenade' w Twoim kierunku rzucona, sorry za gapiostwo :)
przynajmniej z mojej irytacji wyniknal jakis tekst sensowny..

0

przynajmniej z mojej irytacji wyniknal jakis tekst sensowny

i bardzo dobrze, przynajmniej jedna konkretna odpowiedz dla p2004a :-D
pozdrowienia .

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