Kilka dekad temu zajmowałem się programowaniem w C. Próbuję ponownie nauczyć się języka. Ja to napisałem. Dostaję coś nieoczekiwanego. Kiedy zmieniam „short int” na „int”, wydaje się, że działa. Czy ktoś może spojrzeć na mój kod, aby sprawdzić, czy coś jest z nim nie tak, czy jest to problem z kompilatorem. Używam gcc na Linuksie.

#include <stdio.h>

int main(void) {

    short int age = 0;
    short int num_1_yr_olds = 0;
    short int num_2_and_3_yr_olds = 0;
    short int num_above_3_yr_olds = 0;

    while(1) {

        printf ("Enter age: ");
        scanf ("%d", &age);

        if (age < 1) {
            break;
        }

        switch (age) {
            case 1:
                ++num_1_yr_olds;
                break;
            case 2:
            case 3:
                ++num_2_and_3_yr_olds;
                break;
            default:
                ++num_above_3_yr_olds;
                break;
        }
    }
    printf ("Number of 1 year olds = %d\n", num_1_yr_olds);
    printf ("Number of 2 and 3  year olds = %d\n", num_2_and_3_yr_olds);
    printf ("Number above 3 year olds = %d\n", num_above_3_yr_olds);
}

Wejście

Enter age: 1
Enter age: 1
Enter age: 1
Enter age: -1

Wynik

Number of 1 year olds = -1
Number of 2 and 3  year olds = 0
Number above 3 year olds = 0

Wartość num_1_yr_olds się zawala. Spodziewałem się 3, dostaję -1. Wartość num_1_yr_olds staje się -1 niezależnie od danych wejściowych.

c gcc
2
rpat 24 wrzesień 2012, 09:13

2 odpowiedzi

Najlepsza odpowiedź

Twój problem leży tutaj:

short int age = 0;
:
scanf ("%d", &age);

Naprawdę musisz upewnić się, że Twoje typy danych pasują do ciągu formatu. Prawidłowy specyfikator formatu dla short int to %hd, a nie %d.

Niektóre kompilatory faktycznie to sprawdzają i ostrzegają.

Prawdopodobne jest to, że niedopasowanie danych i ciągu formatującego powoduje, że short int staje się „niewłaściwą” wartością, przez co liczby są skręcane.


Bardziej szczegółowo, dla uzupełnienia do dwóch, architektury little-endian, takiej jak x86, skanowanie int do short może umieścić najmniej znaczącą połowę w age, a najbardziej znaczącą połowę w num_1_year_olds (jeśli sąsiaduje z age w pamięci).

Graficznie może być jaśniej myśleć o tym w ten sposób:

                         shorts in memory
                     +-----------------------+
What scanf("%hd") =< |          age          | \
  will write to.     +-----------------------+  = What scanf("%d")
                     |    num_1_year_olds    | /    will write to.
                     +-----------------------+
                     | num_2_and_3_year_olds |
                     +-----------------------+
                     | num_above_3_year_olds |
                     +-----------------------+

Tak więc, kiedy wpiszesz 1, age staje się 1, a num_1_year_olds staje się 0.

Za każdym razem, gdy to zrobisz, zwiększa się num_1_year_olds, ponieważ age to 1, ale zostanie to nadpisane przez scanf następnym razem, gdy otrzymasz dane wejściowe.

Kiedy w końcu wprowadzisz -1 (wszystkie 1 bity w uzupełnieniu do dwóch), age staje się -1, podobnie jak num_1_year_olds.

Następnie, ponieważ age jest mniejsze niż jeden, pętla pęka, a wartości są takie, jakie widzisz: {-1, 0, 0}.

9
paxdiablo 24 wrzesień 2012, 11:07

Próbować

scanf ("%hd", &age);

Ponieważ wiek jest typu short int.

2
Hernan Velasquez 24 wrzesień 2012, 09:15