2016-04-27 13 views
5

Mam znacznie dłuższą tablicę znaków, że zamieniam się w liczby całkowite, ale nie mogę zrozumieć, dlaczego zachowuje się dziwnie w niektórych miejscach.C zamieniające tablice znaków na int zachowujące się dziwnie

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main() 
{ 
    char x[60] = "08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08"; 
    printf("%lu\n\n", strlen(x)); 

    for (int i = 0; i < strlen(x); i+=3) { 
     char num[2]; 
     num[0] = (char)x[i]; 
     num[1] = (char)x[i+1]; 
     printf("%d, ", atoi(num)); 
    } 

} 

Wyjście:

8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 500, 773, 916, 89, 

Wszystko jest super aż ..... 500, 773, 916, 89 ... co się dzieje?

+3

Argumentem "atoi" musi być ciąg znaków. Nie podałeś ciągu. Łańcuch jest ciągiem znaków, po którym następuje bajt zerowy. –

+1

'num [2]' może przyjąć tylko 1 znak, ponieważ drugi będzie "\ 0" '' ' – CinCout

+0

działa idealnie w moim systemie, której wersji' gcc' używasz? –

Odpowiedz

12

Jak widać atoi chce ciąg C: tablica zakończona znakiem zero.

Tak, to

char num[2]; 
    num[0] = (char)x[i]; 
    num[1] = (char)x[i+1]; 

muszą być

char num[3] = {0}; 
    num[0] = (char)x[i]; 
    num[1] = (char)x[i+1];   
    num[2] = '\0'; // this could be avoided in your specific case 
+0

Widzę, co mówisz i to działa, ale czy możesz mi powiedzieć, dlaczego działało 9 razy na 10, a potem zawodzi tylko kilka liczb? – deltaskelta

+1

@deltaskelta Jak to skomentowałem, jest to niezdefiniowane zachowanie, co oznacza, że ​​nie możesz przewidzieć, co się stanie. 'num' jest przydzielane w stosie iw pewnym momencie wykonania 1 bajt po' num [1] 'zmienia jego wartość i podaje te dziwne wyniki. – LPs

+2

Nie, to jest niezdefiniowane zachowanie i wyjaśnienie, co naprawdę się dzieje, wymaga zagłębienia się w szczegóły implementacji (kompilator, procesor, stację wywoławczą, system operacyjny). –

0
num[0] = (char)x[i]; 
num[1] = (char)x[i+1]; 
printf("%d, ", atoi(num) 

ta zakłada, że ​​liczba cyfr w swoim wejściu zawsze będzie 2 (dla których num powinny być zadeklarowane jako char num [3] Wykonaj operację na sucho w logice przy użyciu mniejszego zestawu wejść, na przykład: "01 50"

i=0 
num[0] = *(num+0) = 0 
num[1] = *(num+1) = <space> 
num[2] = *(num + 2) = ????? Since this memory is not allocated for num 
printf("%d, ", atoi("1<space>")) = 1 (atoi stops after looking at num[1] which is a non-digit character) 

i = 3 
num[0] = *(num+0) = 0 
num[1] = *(num + 1) = 0 
num[2] = *(num + 2) = ????? 
printf("%d ", atoi("00<garbage>...")) // this is UB since atoi will definitely read memory at `(num + 2)` which is beyond the bounds of what the compiler allocated for it. 

Spróbuj użyć sscanf, aby przeanalizować dane wejściowe, zamiast polegać na liczbie cyfr. Byłoby to o wiele bardziej czyste i mniej podatne na błędy.

int main() 
{ 
    char x[60] = "08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08"; 
    const char *y = x; 
    char outputBuffer[10]; 
    for(;sscanf(y, "%s", outputBuffer) > 0; y+=strlen(outputBuffer)) printf("%d, ", atoi(outputBuffer)); 
} 
+0

@LPs i gdzie jestem temu zaprzeczeniem? Wspomniałem o tym w odpowiedzi i w przykładzie. OP chciał odpowiedzi na pytanie, dlaczego. Jeśli nie jesteś głosującym, czy mógłbyś rozważyć ponowne przeczytanie mojej odpowiedzi? – bashrc

+0

@LPs num [0] i num [1] = spacja rzeczywiście zostanie przekonwertowana na 1, ponieważ atoi przerwie przetwarzanie po obejrzeniu białych znaków. Pierwsza iteracja to doskonale zdefiniowane zachowanie. – bashrc

0
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main() 
{ 
    char num[3]; // 3rd byte is the null character 
    num[3]='\0'; 
    char x[60] = "08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08"; 
    printf("%lu\n\n", strlen(x)); 

    for (int i = 0; i < strlen(x); i+=3) { 
     strncpy (num, x+i, 2); // Copies two characters starting from x+i 
     // You get a null terminated string num here. 
     printf("%d, ", atoi(num)); 
    } 
printf("\n"); 

} 
+0

@LP: Naprawiono. – sjsam

0

Odpowiedź na Twoje pytanie zostało już zapewnione, to znaczy, że ciąg C jest z definicji NULL zakończone char tablicę. Bez miejsca na terminator NULL, w najlepszym wypadku nie można ufać wynikom łańcucha przekazanego do funkcji łańcuchowej.

Oferuję to tylko po to, aby podkreślić kilka dodatkowych pomysłów na czytanie tablicy char w tablicy int, gdzie terminator NULL staje się prawie nieistotny.

Poniższa metoda obejmuje prostą analizę ciąg i dynamiczne wykorzystanie pamięci, w której zawartość ciągu można odczytać bezpośrednio int pamięci, z pominięciem jakiejkolwiek potrzeby pośrednim buforze ciąg, w wyniku zdolności do czytać legal integer length z łańcucha, i przekształcić bezpośrednio do int:

zobaczyć inline komentarze dla sugestie:

int main(void) 
{ 
    //leave array index blank, the compiler will size it for you 
    char x[] = "08 0223 22 97 382345 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08 1000"; 
    // ^
    int size = sizeof(x)/sizeof(x[0]);//use sizeof macro to get number of elements in array 
    char *tok = NULL; 
    int i = 0; 
    int count=0; 
    for(i=0;i<size;i++) 
    { 
     if(x[i]==' ')count++;//get count to size int array 
    } 
    int *array = malloc((count+1)*sizeof(int)); 
    if(array) 
    { 
     i=0;//reinitialize to 0 for use here 
     tok = strtok(x, " \n"); 
     while(tok)//test after each parse before processing 
     { 
      if((i>0)&&(i%6==0))printf("\n");//newlines to format 
      array[i++] = atoi(tok); 
      printf("%6d, ", array[i]); 
      //  ^provide spacing in output 
      tok = strtok(NULL, " \n"); 
     } 
     free(array); 
    } 
    return 0; 
} 
1

potrzeba odpowiedniego napisu z jej znak null została wysłana przez wielu.

Po prostu chciałem dodać inny pomysł kodowania: dosłowny związek. (char[]) { x[i], x[i + 1], '\0' } do realizacji tego.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(void) { 
    char x[] = "08 02 22 97 38 15 00 40 00 75 04 05 07 78 52 12 50 77 91 08"; 
    size_t len = strlen(x); 
    printf("%zu\n\n", len); 

    for (size_t i = 0; i < len; i += 3) { 
    printf("%d, ", atoi((char[]) { x[i], x[i + 1], '\0' })); 
    } 
} 

Wyjście

59 

8, 2, 22, 97, 38, 15, 0, 40, 0, 75, 4, 5, 7, 78, 52, 12, 50, 77, 91, 8, 

Niektóre inne poprawki wykonane zbyt.