2017-01-20 23 views
3

下の2つの構造体フィールド定義が互いにどのように区別されるか。fscanf/sscanf文字列を構造体フィールドに渡すchar [4]

//first struct  
typedef struct{ 
    char *name; //here is the difference 
    int shares; 
} STOCK1; 


//second struct 
typedef struct{ 
    char name[4]; //here is the difference 
    int shares; 
} STOCK2; 


//here inside main() 
FILE *fpRead = openFile(input_filename, "r"); 

STOCK1 s1; 
fscanf(fpRead, "%s %d", s1.name, &s1.shares); 
printf("%s %d ", s1.name, s1.shares); 

STOCK2 s2; 
fscanf(fpRead, "%s %d", s2.name, &s2.shares); 
printf("%s %d ", s2.name, s2.shares); 

コードが印刷されます:

MSFT 400 
MSFT� 400 

2番目の構造体を使用して見ることができるように、それは文字列の後、いくつかのガベージ文字を印刷します。何故ですか?

入力文字列:

MSFT 400 
YHOO 100 
... 
STOCK2.name
+0

'char name [4];' - > 'char name [5];'以上です。また、使用前に 's1.name'に割り当てる必要があります。 – BLUEPIXY

答えて

1

2つのstruct定義の違いは、1つのstructにストレージをあらかじめ割り当てておき、もう1つのstructにポインタを宣言していることです。

最初のstructには、char *があります。 char *はポインタです。それは何かを指していません。あなたはいくつかのメモリを動的に割り当てる必要がありますし、あなたのchar *ポインタがその割り当てられたメモリを指していることを指します。

structにはchar name[4]があります。これは配列で、この配列には4バイトが割り当てられます。これは割り当てられ、使用の準備ができています。

バッファのサイズがわからない場合は、最初にstructを使用してください。 mallocを使用して、1024バイトなどの任意の量のメモリを割り当てます。その後、一度に1024バイトのデータを読み込みます。データの合計量を計算できるようになるまでこれを続けてください。その後、mallocを使用してその量のメモリを割り当ててから、データを読み込みます。

データが常に4バイトの長さであり、決してそれより大きくても小さくてもわからない場合は、2番目のstructを使用してください。あなたが望むなら、それを次のように宣言することができます:char name[500]。これはあなたのために500バイトをあらかじめ割り当てて、あなたの文字列が499文字より大きくない限り、これは動作します。しかし、あなたは記憶を浪費している可能性があります(これは最近大きな問題ではありません)。この問題を克服する最も効率的な方法は、実際に必要とするメモリ量を動的に割り当てることです。malloc

最後の警告が1つ....文字列自体には十分なメモリが必要です。例:

/* I am allocating 5 bytes to store my name. 
    My name is Alan, so I'm allocating 4 bytes 
    plus 1 additional byte for the null terminator 
*/ 

char myName[5]; 
myName[0] = 'A'; // A 
myName[1] = 'l'; // l 
myName[2] = 'a'; // a 
myName[3] = 'n'; // n 
myName[4] = '\0'; // Null Terminator 

printf("%s", myName); // Prints Alan 
1

の大きさが4つの文字です。あなたの文字列はこの4文字+ターミネーター文字\0を持っています。これは5文字です。したがって、ターミネータは、sharesコンポーネントと重複する構造コンポーネントの背後にあります。 sharesコンポーネントを設定すると、文字列ターミネータが上書きされます。

これを説明するためのレイアウト例を示します(32ビット/ 4バイト整数)。名前を書いた後:

n+0 name[0] M 
n+1 name[1] S 
n+2 name[2] F 
n+3 name[3] T 
n+4 shares \0 <- terminator 
n+5 shares 
n+6 shares 
n+7 shares 

n+0 name[0] M 
n+1 name[1] S 
n+2 name[2] F 
n+3 name[3] T 
n+4 shares 144 | Example for 400 stored in a 32-bit int (144+1*256) 
n+5 shares 1 | 
n+6 shares 0 | 
n+7 shares 0 | 

ターミネータがなくなっているとprintf()、この問題を解決する名前コンポーネントのサイズを変更するにはT.

後に文字を書いて続けています。

BTW:ファイルを無制限に読み込むと、バッファオーバーフローでソフトウェアを攻撃することができます。

+0

イラストは非常に明確で有用です!ありがとう! – bing

関連する問題