2016-04-27 20 views
5

私は整数に変わっているはるかに長いchar配列を持っていますが、なぜいくつかの点で奇妙な動作をする理由を理解できません。C char配列をintに変える

#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)); 
    } 

} 

出力:

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

すべてが素晴らしいですまで..... 500、773、916、89 ...何が起こっているのでしょうか?

+3

'atoi'の引数は文字列でなければなりません。あなたは文字列を入力しませんでした。文字列は、一連の文字の後にnullバイトが続きます。 –

+1

'num [2]'は1文字しか使用できません。もう1つは '\\ 0 'です – CinCout

+0

私のシステムでは完全に動作します。どのバージョンのgccを使用していますか? –

答えて

12

ご覧のとおり、atoiは、C文字列を要求しています。ヌルで終わる文字配列です。

ので、この

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

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

あなたは何を言っているのかは分かりませんが、10回中に9回働いていたのはなぜですか? – deltaskelta

+1

@deltaskelta私がコメントしたように、未定義の振る舞いは、何が起こるかを予測できないことを意味します。 'num'は割り当てられたスタックであり、' num [1] 'の後の最初のバイトはその値を変更し、それらの奇妙な出力を与えます。 – LPs

+2

いいえ、それは未定義の振る舞いです。実際に何が起こっているのかを説明するには、実装の詳細(コンパイラ、プロセッサ、コールスタック、OS)をダイブする必要があります。 –

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

であることをこれはあなたの入力の桁数が常にnumがcharとして宣言する必要のある2(になることを前提としていたことがありますnum [3]。より小さな入力セットであなたのロジックのドライランを実行します。例えば、"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. 

桁数に頼るのではなく、sscanfを使用して入力を解析してみてください。それははるかにクリーンで、エラーを起こしにくいでしょう。

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と私はそれを否定していますか?私は答えとその例で言及しました。 OPは理由を求めて、その理由に答えました。あなたがダウン投票者であれば、もう一度私の答えを読むことを検討してもらえますか? – bashrc

+0

@LPs num [0]とnum [1] = spaceは実際には1に変換されます。なぜならatoiは空白を見て処理を停止するからです。最初の反復は完全に定義された動作です。 – 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

@LPs:これが修正されました。 – sjsam

0

あなたの質問への答えがすでに提供されている、すなわちC文字列がNULLがchar配列を終了し、定義によってです。 NULLターミネータのためのスペースがなければ、文字列関数に渡された文字列の結果は、せいぜい信用できません。

charアレイをintアレイに読み込む際のいくつかの追加アイデアを強調するために、これを提供しています。ヌルターミネータはほとんど問題になりません。

以下の方法は、文字列から任意legal integer lengthを読み取る能力が得られ、中間文字列バッファの必要性をバイパスして、単純な文字列解析、文字列の内容がintメモリに直接読み込ま取得ダイナミックメモリ使用を含みますそしてintに直接変換:

が提案をインラインコメントを参照してください:

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

そのヌル文字で適切な文字列の必要性は、多くによって投稿されました。

別のコーディングアイデアを追加したかっただけです:複合リテラル。それを実装するために(char[]) { x[i], x[i + 1], '\0' }

#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' })); 
    } 
} 

出力

59 

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

他のいくつかの修正も行いました。