Zmiana z if(a=true) na if(a) powoduje runtime error

0
 #include <stdio.h>
#include <conio.h>
void foo();
int main()
{
	foo();
	return 0;
}
void foo()
{
	char s[3], next;
	short count=0;
	bool a=false;
	for(int i=0; i<3; ++i)
	{
		printf("Czy %d. sedzia jest na tak? (t/n)\n",i+1);
		scanf("%s",&s[i]);
		if(s[i]=='t')count++;
	}
	printf("%d sedziow jest na tak.",count);
	if(count>=2)printf(" Zawodnik przechodzi do nastepnej rundy.\n");
	else printf(" Zawodnik nie przechodzi do nastepnej rundy.\n");
	printf("Nastepny zawodnik? (t/n)\n");
	scanf("%s",&next);
	if(next=='t')a=true;
	if(a=true)foo();
} 

Jeśli w przedostatniej linijce jest if(a=true)foo(); to program działa. Gdy jest usuniete "=true" to jest takie coś:
Odpalenie programu: wpisanie 'g', enter i tak trzy razy i pokazuje sie error "Run-Time Check Failure #2 - Stack around the variable 'next' was corrupted."
Taki sam error jeśli bym nie miał w programie zmiennej "a" i by na końcu by było tylko if(next=='t')foo();
Kompilowane w Visual C++ 2010 Express. Kolega na linuxie nie ma żadnych errorów z tym programem, niezaleznie od tego co jest w przedostatniej linijce.

1

if(a=**=**true)

No chyba ze do "a" chcesz przypisać prawdę.

EDIT:
Mam więcej pytań:
dlaczego "g"
co jest w next na poczatku?

0

Wydaje mi się, że scanf("%s",&next) jest niepoprawne. %s wczytuje stringa (tablicę charów), a Ty masz pojedynczego chara. Zastanawiam się, czy nie może być tak, że scanf próbuje coś zapisywać pod adresami dalszymi niż &next, i stąd runtime error związany z next.

EDIT: Jasne, przecież jak scanf wczytuje stringa (%s), to zakańcza go \0. Więc zapisuje ci \0 w adresie zaraz po &next, nawet gdy podasz mu tylko jeden znak. Czyli tam, gdzie nie ma prawa niczego zapisywać. Jeśli działa na Linuxie, to chyba tylko przez przypadek.

Powinno być scanf("%c",&next). Sprawdź, czy wtedy będzie działać.

0
docxxx napisał(a):

if(a=**=**true)

No chyba ze do "a" chcesz przypisać prawdę.

EDIT:
Mam więcej pytań:
dlaczego "g"
co jest w next na poczatku?

co za nubski blad... tak, powinno byc == i wtedy nie ma roznicy czy jest if(a), czy if(a==true), w obu przypadkach jest wtedy ten sam blad. Zreszta gdy było te if(a=true), to co prawda nie wyskakiwal error, ale wtedy gdy program powinien sie zakonczyc (gdy next nie jest 't'), to lecial dalej, wiec nie dzialal poprawnie.

"g" tylko dlatego ze jest inne niz "t". moze to byc kazda inna litera, tylko oprocz "t".

własnie zła inicjalizacja sprawiala ten problem. teraz zamiast osobnego next, wykorzystuje w tym ostatnim ifie s[0](co raczej nie jest dobra praktyką, ale działa i zaoszczedzilem pare bajtow hehe) i zainicjowałem ta tablice charow normalnie czyli tak: char* s=new char[3]; i teraz jest dobrze.

Wydaje mi się, że scanf("%s",&next) jest niepoprawne. %s wczytuje stringa (tablicę charów), a Ty masz pojedynczego chara. Zastanawiam się, czy nie może być tak, że scanf próbuje coś zapisywać pod adresami dalszymi niż &next, i stąd runtime error związany z next.

EDIT: Jasne, przecież jak scanf wczytuje stringa (%s), to zakańcza go \0. Więc zapisuje ci \0 w adresie zaraz po &next, nawet gdy podasz mu tylko jeden znak. Czyli tam, gdzie nie ma prawa niczego zapisywać. Jeśli działa na Linuxie, to chyba tylko przez przypadek.

Powinno być scanf("%c",&next). Sprawdź, czy wtedy będzie działać.

jak zmienie na %c to program sie sam zamyka Od razu przy wyswietlaniu ilu sedziów głosowalo na tak. jak zmienie na %c w tym poprzednim scanf w pętli, to po odpowiedzi na pierwsze pytania, Od razu się pokazuja dwa nastepne pytania, tak: user image

%s działa dobrze.

1
TadzikT napisał(a):

zainicjowałem ta tablice charow normalnie czyli tak: char* s=new char[3];

Nie ma nic złego w inicjacji char s[3]. Jeśli koniecznie chcesz alokować tę tablicę dynamicznie, to pamiętaj, by później zwolnić pamięć.

TadzikT napisał(a):

jak zmienie na %c to program sie sam zamyka Od razu przy wyswietlaniu ilu sedziów głosowalo na tak. jak zmienie na %c w tym poprzednim scanf w pętli, to po odpowiedzi na pierwsze pytania, Od razu się pokazuja dwa nastepne pytania

Bo scanf("%c"), wczytując pojedynczy znak, pozostawia na wejściu niewczytanego entera (znak nowej linii, \n), którego nacisnąłeś. Co oznacza, że następne wywołanie scanf wczytuje ten właśnie znak nowej linii, i traktuje to jako Twój input.
Rozwiązania są dwa:

  1. Po scanf("%c", &zmienna_typu_char) piszesz pojedynczy getchar(), żeby usunąć z bufora wejścia ten znak nowej linii.
  2. Wczytywać stringa jak poprzednio, ale wtedy MUSISZ wczytywać do tablicy znaków, a nie pojedynczego znaku! Czyli na przykład:
char t[5];
scanf("%4s",t);

...
3) Może to Twoje <conio.h> coś jeszcze udostępnia, nie wiem, nie znam się na <conio.h>.

TadzikT napisał(a):

%s działa dobrze.

Nie, NIE działa dobrze. A jeśli, to tylko przez przypadek.

Jak bardzo to jest złe rozwiązanie, możesz zobaczyć na tym prostym przykładzie:

#include <stdio.h>

int main()
{
  char c;
  scanf("%s", &c);
  puts(&c);
}

Uruchom ten program i wpisz mu np. asdf jako input. I magia! Jeśli program się nie wysypał (o dziwo), to zobaczysz, że wypisze Ci asdf a nie a. Jak on mógł zapamiętać 4 litery, jeśli dałeś mu pamięć tylko jednego znaku? Możesz też dać mu dłuższy input. U mnie asdf się jeszcze nie wysypuje, ale już jak wpiszę asdfasdfasdf to dostaję Runtime Error.

Naprawdę: To co robisz, jest niepoprawne i może działać TYLKO przez przypadek!

0

Użyłem dynamicznej lokacji tej tablice, bo inne sposoby dawały ten błąd runtime. Dynamiczny nie dawał, ale jak już chciałem go potem usuwać to wtedy też był ten błąd. Wiec niby działa, ale tylko jak nie usuwam tablicy dynamicznie, wiec dalej nie jest dobrze. Teraz zrobiłem tak jak napisałeś, czyli inicjalizacja char s[3];, %c i getchar() i dalej nie jest idealnie. Jesli sie wpisuje tylko pojedynczy znaki to jest ok, ale jak wpisze kilka to sie dzieje to user image

1

No cóż, faktycznie ten kod jest mało „głupoodporny” – zakłada, że faktycznie otrzyma tylko 1 znak na wejściu.
Jeśli tych znaków jest więcej, to dzieje się to samo, co wcześniej: „nadmiarowe” znaki pozostają w buforze wejścia i zostają odczytane przy następnym wywołaniu scanf (a Ty nawet nie masz szansy nic wpisać).
Jeśli faktycznie chcesz to zrobić porządnie, to trzeba ręcznie pousuwać z bufora wejścia wszystkie nadmiarowe znaki. Wyglądałoby to jakoś tak:

EDIT: Delikatnie uprościłem kod

#include <stdio.h>
#include <ctype.h> // isalnum

int main()
{
  char c = '\0'; // Początkowa wartość. Ważna: jeśli niczego nie uda się wczytać, to nie chcemy, żeby w c była jakaś losowa wartość. W przeciwnym razie możemy pomylić poprzednią wartość c z sensownym inputem użytkownika. Trzeba pamiętać, by zerować c za każdym razem, gdy chcemy coś do niego wczytać.
  while(!feof(stdin) && !isalnum(c)) // Kontynuujemy próbę wczytywania tak długo, jak długo możemy, a na nie udaje nam się wczytać niczego poprawnego (feolf(stdin) - zwraca true, jeśli wejście zostało zamknięte; isalnum(c) - sprawdza, czy c jest znakiem alfanumerycznym, tj. jest cyfrą lub literą). Mamy też odporność na sytuację, że użytkownik naciśnie ENTER niczego nie wpisując - wtedy wczytamy znak nowej linii '\n', który nie przejdzie testu isalnum.
    c = getchar(); // Wczytanie znaku do c
  while(!feof(stdin) && getchar() != '\n'); // Ignorujemy wszystkie nadmiarowe znaki w tej linii, włącznie ze znakiem '\n'. Następna próba wczytywania będzie pobierać znaki z nowej linii.
  if(!isalnum(c)) // Mimo usilnych prób nie udało się nic wczytać, można kończyć działanie
    return 1; // Kończymy działanie z błędem
  
  // Robimy co trzeba z poprawnie wczytanym znakiem c, kontynuujemy działanie normalnie; możemy np. wypisać ten znak:
  printf("%c\n",c);
}

Nie jestem pewien, czy nie przekombinowałem, czy jakoś prościej nie dałoby się tego zrobić. Być może z użyciem funkcji z conio.h dałoby się to zrobić łatwiej, nie wiem, nie znam się na conio.h. EDIT: Zdaje się, getch z conio.h faktycznie niektóre problemy załatwi.

EDIT: Właściwie, to nadal nie jest idealnie, bo program odrzuca polskie znaczki...

0

O kurde, ale ten I\O w C jest problematyczny. Już raczej nie będę kombinować z tym programem, jest wystarczająco dobrze, niech będzie jak jest. Finalnie wygląda to tak:

#include <stdio.h>
void foo();
int main()
{
	foo();
	return 0;
}
void foo()
{
	char s[3], count=0;
	for(int i=0; i<3; ++i)
	{
		printf("Czy %d. sedzia jest na tak? (t/n)\n", i+1);
		scanf("%c", &s[i]);
		getchar();
		if(s[i] == 't') count++;
	}
	printf("%d sedziow jest na tak.", count);
	if(count >= 2) printf(" Zawodnik przechodzi do nastepnej rundy.\n");
	else printf(" Zawodnik nie przechodzi do nastepnej rundy.\n");
	printf("Nastepny zawodnik? (t/n)\n");
	scanf("%c", &s[0]);
	getchar();
	if(s[0] == 't') foo();
}

Dzięki za pomoc.

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