2016-01-25 16 views
10

Mam pętlę, która musi przejść od j do 0 (włącznie). Moja zmienna j jest typu size_t, która jest zwykle niepodpisana.iterowanie tablicy w tył w Warunek pętli For zatrzymany na 0 przy użyciu liczb całkowitych bez znaku powodującego nieskończoną pętlę

Mój kod:

#include<stdio.h> 
#include<conio.h> 

#define SIZE 100 

int main(){ 
    char str[SIZE]; 
    size_t i=0; 
    size_t j; 
    puts("Enter any string"); 
    scanf("%s",str); 
    while(str[i]!='\0'){ 
     i++; 
    } 


    for(j=i-1;j>=0;j--){ 

     printf("%c",str[j]); 
    } 


    getch(); 
    return 0; 
} 

uzyskać nieskończoną pętlę. Jeśli usunę równość zerową, wyprowadza on odwrotność łańcucha bez pierwszej litery. więc jaki jest problem?

Odpowiedz

6

size_t jest liczbą całkowitą bez znaku i nigdy nie będzie mniejsza niż 0. Więc stan w for pętli jest zawsze prawdziwe:

for(j=i;j>=0;j--) 

Można zmodyfikować warunek (trochę brzydki chociaż):

for(j=i; j-- > 0;){ 
    ... 
} 

pamiętać, że w swoim stanie, jesteś Drukowanie \0 NULL również bajt, który jest niedrukowalny. (ponieważ j rozpoczyna się od wartości równej długości ciągu znaków). Powyższy warunek również się tym zajmuje.

również:

  • można użyć strlen() zamiast zapętlenie nad nim siebie.
  • Sprawdź wartość zwracaną przez scanf(), jeśli wprowadzono poprawne odczytanie wejścia.
+0

Tak zauważyłem, że j powinna rozpocząć formularz I-1 i naprawiłem dziękuję –

+0

Dziękuję mój problem jest rozwiązany wiele rozwiązań i wiem, że mogę używać strlen() .. Ale proszę, możesz wyjaśnić, dlaczego kod mu powoduje nieskończoną pętlę ?? i dlaczego jeśli po prostu zastąpię size_t przez int wynik będzie poprawny? Jaki jest problem z size_t? Przypuśćmy, że pętla dochodzi do j = 0, powinna wydrukować element zero, a potem powinno wyjść, ponieważ warunek będzie fałszywy, więc dlaczego wchodzi w nieskończoną pętlę ?? –

+1

'size_t', liczba całkowita bez znaku nie może mieć wartości mniejszej niż 0. Tak więc, jeśli zrobisz j-- gdy j ma wartość 0, to stanie się SIZE_MAX (maksymalna wartość size_t może pomieścić). Powiedzmy, że SIZE_MAX to 4294967295, wtedy pętla uruchomi się z j -> 0 -> 4294967295 -> 0 ->, a cykl się powiedzie. jeśli użyjesz 'int', to będzie działać zgodnie z oczekiwaniami. Ale 'size_t' jest właściwym typem, którego używa się do znalezienia długości łańcucha. Stąd otrzymujesz nieskończoną pętlę. jeśli użyjesz 'int', to będzie działać zgodnie z oczekiwaniami. Ale "size_t" jest właściwym typem, którego używa się do znalezienia długości ciągu znaków. –

2

Liczba całkowitych znaków nie będzie zawijana w C. Liczba całkowita bez znaku jest zawsze równa lub większa od 0, w kodzie: uint >= 0, jest zawsze prawdziwa.

Możesz użyć porównania z SIZE_MAX, ponieważ jest to największa wartość dla typu size_t. Kod będzie iterować i wydrukować do 0, tak jak powinien, a następnie zawinąć do SIZE_MAX, a pętla się zakończy. (Zakładamy, że długość łańcucha nie jest równa SIZE_MAX.)

for(j=i; j < SIZE_MAX ;j--){ 

    printf("%c",str[j]); 
} 

Pamiętaj również, że twój kod wypisze znak null. Tak więc indeks początkowy powinien być j=i-1, który działa ładnie z zachowaniem owijania, ponieważ jeśli długość łańcucha wynosi 0, pętla for nie wypisze niczego, ponieważ i-1 == SIZE_MAX.

9
for(j=i; j>0; j--) { 
    printf("%c", str[j-1]); 
} 

Byłaby to inna opcja.
Dla początkującego może być łatwiejszy do zrozumienia.
Ale inne odpowiedzi będą lepsze.

edytuj: powiedziałbym, że najlepsze będzie for(j=i; j-- > 0;) przez l3x.
dekrementacja j po sprawdzeniu, czy jest większa niż 0.

Używanie pętli do {} while() również zadziałałoby.

j = i; 
do { 
    j--; 
    printf("%c", str[j]); 
} while (j > 0); 
+1

To wygląda jak zwykły przykład brzydkiego kodu z dziwnym formatowaniem. – Malina

5

Można zmienić j z size_t do long Daje to pewność, wszystkie dane nadal pasuje i można osiągnąć wartość -1.

Inną opcją jest do końca dla pętli z następującym stwierdzeniem:

for (j = i - 1;;--j) 
{ 
    // code 
    if (j == 0) break; 
} 

tak na marginesie: Twoja pierwsza pętla robi to samo jako strlen() w string.h.

+0

'j = i; robić { ...; jot--; } while (j! = 0); 'jest prawdopodobnie bardziej czytelny. – Lundin

3

Pętle zliczające w dół wydają się być nieco niejasne i trudne do odczytania. Rozważyć użycie tej alternatywy zamiast:

const size_t max = i-1; // maximum value that j can have 

for(j=0; j<=max; j++) 
{ 
    ... str[max-j]; 
} 
0

wartość bez znaku otacza więc kiedy j == 0 i pętla robi j--, j >= 0 jest nadal prawdziwe.

Rozwiązanie proste i łatwe do odczytania idzie tak:

void reversePrint(char str[]) 
{ 
    size_t j = strlen(str); 
    while (j-- > 0) 
     printf("%c", str[j]); 
} 

drukuje ciąg w odwrotnej kolejności: olleH.

+0

Downwotnicy, czy można wyjaśnić? – Chnossos

+0

Ale nie w dół, myślę, że nie podobał im się sposób, w jaki mówisz * "... łatwe do odczytania rozwiązanie brzmi jak ..." *: '.. gdy (j -> 0) ..." które sprawi, że użytkownicy [zadaj to pytanie] (http://stackoverflow.com/questions/1642028/what-is-the-name-of-the-operator-in-c-); A po drugie, twoje niezwykłe użycie 'strlen 'na * ciągu literalnym *,' str' którego długość jest znana w czasie kompilacji. – WhiZTiM

+0

Dostaję twój punkt. Może ta edycja by zrobiła? – Chnossos

1

Problemem jest to, że jest zawsze truej >= 0 ponieważ j jest unsigned.

Kiedy odliczanie do zera z unsigned, ja zwykle korzystam postfix --:

while (j-- > 0)