No.6ベストアンサー
- 回答日時:
★全く分からんのですか?
>としたあとにどのように入れたらよいかがわかりません…
↑
これは文字列の表現の仕組みを理解していれば出来ると思います。
回答者 No.2 さんの補足にあるソースで strcpy() 関数を使わなでコピーすれば
上手くいくようになります。もちろんすべてが正しいわけではなく、考え方が
大よそあっているという事です。
HNDHDKさんのソース
while(fgets(string,128,fp)){
for(n=0;string[n]!=" ";n++){
strcpy(list[i].name,string[n]);
}
for(n=n+1;string[n]!=" ";n++){
list[i].age=;
}
for(n=n+1;string[n]!='\0';n++){
strcpy(list[i].name,string[n]);
}
}
これを strcpy() 関数を使わないで処理すると
while ( fgets(string,128,fp) != NULL ){
for ( n = 0 ; string[n] != ' ' ; n++ ){ ←スペースは文字定数で比較(文字列ではない)
list[ i ].name[ n ] = string[ n ];
}
list[ i ].name[ n ] = '\0'; ←末尾の'\0'(重要)
list[ i ].age = 0; ←ゼロを入れておく
for ( n++ ; string[n] != ' ' ; n++ ){ ←ここも文字定数で比較
list[ i ].age *= 10;
list[ i ].age += (string[n] - '0'); ←文字から数値に変換
}
for ( n++ ; string[n] != '\0' ; n++ ){
list[ i ].job[ n ] = string[ n ];
}
list[ i ].job[ n ] = '\0'; ←ここも末尾の'\0'(重要)
}
となります。
最後の要素は job メンバに入れるように修正しておきました。
こんな感じでいいです。
strcpy() 関数を使いたい場合は区切り文字(スペース)に '\0' をセットしてから
文字列の先頭を strcpy() 関数に渡すことでコピーできます。今回は文字単位で
コピーする方法を紹介しました。改良してみて下さい。
>ageはint型なのでどのようにしたら?
これも区切り文字(スペース)に '\0' をセットした後に atoi() 関数で文字列から
整数値に変換できます。今回は文字単位で整数値に変換してみました。
それが次の2行です。
>list[ i ].age *= 10;
>list[ i ].age += (string[n] - '0'); ←文字から数値に変換
このようにすることで文字列から整数値に変換できます。
最後に:
文字定数と文字列定数を混同しないように注意して下さい。
また、文字の比較と文字列の比較も違いますので同じに考えないで下さい。
C言語では文字列の比較にstrcmp()関数で行います。
この回答への補足
Oh-Orangeさん
>list[ i ].age *= 10;
>list[ i ].age += (string[n] - '0'); ←文字から数値に変換
の2行が理解しがたいのですが…これは、
決まりみたいなものなのでしょうか?
特に上の行の10を代入の意味は???
No.9
- 回答日時:
★回答者No.6です。
・デバッグしてみました。
どうやら回答 No.6 のサンプルに一部間違いがありました。
それが原因で文字化けしていました。
修正版:
for ( j = 0, n++ ; string[n] != '\n' ; n++, j++ ){
list[ i ].job[ j ] = string[ n ];
}
list[ i ].job[ j ] = '\0';
修正箇所1:
・job 配列の添え字に n を使っていたのが間違いです。
正しくは新しいカウンタ変数 j などを用意して添え字が 0 から始まるようにします。
これにより最後の '\0' も job[ j ] = '\0'; と j カウンタに変更します。
修正箇所2:
・for()文の条件式で string[n] != '\0' としていましたが、改行を job 配列に
含めないようにするため string[n] != '\n' と変更して下さい。
修正箇所3:
・meibo 構造体の job のサイズが 5 です。
質問にあるテキストファイル(meibo.txt)には『公務員』『学生』ですよね。
『学生』はともかく『公務員』はサイズが 6 です。'\0'文字も含めると 7 になります。
配列の容量が不足しています。job[ 10 ]; ぐらいに変更して下さい。
上記の3箇所を修正すれば正しく動きました。
なおスペースが 2 個以上連続していたり、名前が 9 文字以上だったり、または
職業名が 4 文字以上だと name、job の配列容量を越えます。この辺のチェックを
付け加えた方が良いでしょう。あとポインタを使ったり、strcpy()、atoi() 関数を
使って処理させる方法もあります。いろいろと工夫してみてください。
>Oh-Orangeさん
本当に丁寧な解説ありがとうございました☆☆☆
おかげでこのやり方でもうまく表示できました(^o^)
Oh-Orangeさんのお陰で、
文字列の処理(入門)の仕方が
かなりわかりました(^o^)b
今度は自分の文字列処理の仕方を
見つけて、知識を深めたいと思います☆
ありがとうございました☆
No.8
- 回答日時:
★回答者No.6です。
・補足より。文字列から整数値の変換の仕方を書きます。
>>list[ i ].age *= 10;
>>list[ i ].age += (string[n] - '0'); ←文字から数値に変換
>
>の2行が理解しがたいのですが…これは、
>決まりみたいなものなのでしょうか?
>特に上の行の10を代入の意味は???
↑
これを次のように書き換えてみます。
char str[] = "123";
int age = 0; ←初期化
for ( i = 0 ; str[i] != '\0' ; i++ ){
age = (age * 10) + (str[i] - '0');
}
とします。また、
>age = (age * 10) + (str[i] - '0');
の行は次の2行でも同じ処理になります。記述が違うだけ。
age *= 10;
age += (str[i] - '0');
こういうことです。
・それではfor文を展開してみます。
i=0のとき age = (age * 10) + ('1' - '0'); … age = 0 + 1;⇒age=1
i=1のとき age = (age * 10) + ('2' - '0'); … age = 10 + 2;⇒age=12
i=2のとき age = (age * 10) + ('3' - '0'); … age = 120 + 3;⇒age=123
となって age = 123 がセットされます。
この仕組みが『文字列から整数値の変換』の決まりみたいな方法です。
・以上。
この回答への補足
Oh-Orangeさん
ありがとうございます☆
とてもすばらしい解説でした(*^o^*)
しかし、Oh-Orangeさんのプログラムを参考に作ってみたのですが、
どうしても job が文字化けしてしまいます(T_T)
どこがおかしいでしょうか?
#include <stdio.h>
#include <stdlib.h>
#define PROF 256
int main(void)
{
struct meibo{
char name[20];
int age;
char job[5];
}list[10];
char FileName[20];
unsigned char string[PROF];
int i=0,j,n;
FILE *fp;
printf("入力ファイル名>>>");
scanf("%s",FileName);
if((fp=fopen(FileName,"r"))==NULL)
{
printf("ファイルが見つかりません。---%s\n",FileName);
exit(EXIT_FAILURE);
}
while(fgets(string,PROF,fp)!=NULL)
{
for(n=0;string[n]!=' ';n++)
{
list[i].name[n]=string[n];
}
list[i].name[n]='\0';
list[i].age=0;
for(n++;string[n]!=' ';n++)
{
list[i].age*=10;
list[i].age+=(string[n]-'0');
}
for(n++;string[n]!='\0';n++)
{
list[i].job[n]=string[n];
}
list[i].job[n]='\0';
i++;
}
for(j=0;j<i;j++)
{
printf("%s %d %s\n",list[j].name,list[j].age,list[j].job);
}
fclose(fp);
return EXIT_SUCCESS;
}
No.7
- 回答日時:
初心者向きなら
以下のようなfscanfを使うやり方もあります
int i;
FILE *fp
fp = fopen("meibo.txt", "r");
i = 0;
while (!feof(fp))
{
fscanf(fp,"%s %d %s",list[i].name,&(list[i].age),list[i].job);
i++;
}
尚、プロは、scanfやfscanfの使用は嫌うようです。
gyrocompasさん
初心者なので、このような解説もとてもありがたいです☆
シンプルなのですぐに組み込んでみたいと思います☆
No.5
- 回答日時:
> while(string!=" ")
これは、ローカル変数のstringの「アドレス」と、プログラム中のどこかに確保された
" "(メモリ上では 0x20 0x00)の「アドレス」を比較しています。
結果が等しくない時に真となりますので、ここの条件判定は常に真です。
# 値の書き換わる変数と、文字列定数の先頭アドレスが同一になることは絶対にありませんので。
表示されないのは、
strcpy(list[i].name,string);
を無限ループで実行しているため、ここから先に進まないからではないでしょうか。
文字列の比較はstrcmp()を使用しましょう。
# C++の文字列クラスの場合、string!=" "と言う判定が可能になっている場合がありますが。
No.4
- 回答日時:
★デリミタは、半角空白(0x20)ひとつとする。
★最大レコード長は255バイトとする。
★名前、職業には半角空白を含めない。
★レコード数は30以内。
のファイルの条件があり、
★構造体の職業項目には、復帰改行コードを含めない(◆)。
の作成仕様があるとき、
☆基本部分のみでは、説明できないので・・ほぼ「丸受け」?
#define un_char unsigned char
typedef struct{
int iAge;
char cName[16];
char cJob[32];
}LIST;
int toStruct( int iCntSpace, LIST sWork[], int nn, un_char cBuf[], int iTop )
{
int i, iCnt = 0;
for( i = 0; i < 256; i++ ){
if( 0x0D >= cBuf[i] ) cBuf[i] = 0x20; // 復帰改行コード(◆)
if( 0x20 == cBuf[i] ) iCnt++; // 0x20 デリミタ
if( iCnt == iCntSpace ){
cBuf[i] = 0x00; // 要素の末端
if( 1 == iCnt ) strcpy( sWork[nn].cName, &cBuf[iTop] );
if( 3 == iCnt ) strcpy( sWork[nn].cJob, &cBuf[iTop] );
if( 2 == iCnt ) sWork[nn].iAge = atoi( &cBuf[iTop] );
return( i + 1 ); // 次の要素の先頭
}
}
return( 0 );
}
void main()
{
LIST sWork[30];
int i, nn = 0, iTop;
FILE *fp1;
un_char cBuf[256];
fp1 = fopen( "meibo.txt", "r" );
// File check(略)
while( NULL != fgets( cBuf, 255, fp1 ) ){
iTop = toStruct( 1, sWork, nn, cBuf, 0 );
iTop = toStruct( 2, sWork, nn, cBuf, iTop );
iTop = toStruct( 3, sWork, nn, cBuf, iTop );
nn++;
}
fclose( fp1 );
for( i = 0; i < nn; i++ ){
printf( "%-10s %2d %s\n", sWork[i].cName, sWork[i].iAge, sWork[i].cJob );
}
}
注:インデントに全角空白を用いています。
yama5140さん
この間の質問といい、たびたびありがとうございます☆
サブ関を使ったやり方ですね☆
参考にさせていただきます☆
No.3
- 回答日時:
>ageはint型なのでどのようにしたら?
じゃあ、ひとまずコイツは list[i].age = 0; にしといて、コンパイルしてみよか。
エラーが出ると思うので strcpy のマニュアルなどみつつ修正して下さい。
この回答への補足
なんとかコンパイルまでこぎつけました☆
現段階でのプログラムはこんな感じなんですが、
表示がされなくて…
while(fgets(string,PROF,fp))
{
while(string!=" ")
{
strcpy(list[i].name,string);
}
while(string!=" ")
{
list[i].age=0;
}
while(string!='\0')
{
strcpy(list[i].male,string);
}
i++;
}
for(i=0;i<5;i++)
{
printf("%s %d %s\n",list[i].name,list[i].age,list[i].male);
}
ご指導お願いします!!!
koko_u_さん
皆様の解説とを参考にしながら、ようやく表示に成功しました!!
理解力に乏しい自分に何度も解説していただき
本当にありがとうございましたm(_ _)m
No.2
- 回答日時:
>中の処理は、
>
>strcpy(list[i].name,~);
>
> みたいなことこですか?
ま、こういうのは「正解」はないので、
まずは自分の知っている関数を使ってとにかく動くコードを書きましょう。
strcpy はコピー元の文字列で '\0' が現れるまでをコピーしますね。
「田中」までをコピーするにはどうすればよいか考えましょう。
はい。補足にどうぞ。
この回答への補足
while(fgets(string,128,fp))
{
for(n=0;string[n]!=" ";n++)
{
strcpy(list[i].name,string[n]);
}
for(n=n+1;string[n]!=" ";n++)
{
list[i].age=;
}
for(n=n+1;string[n]!='\0';n++)
{
strcpy(list[i].name,string[n]);
}
}
こんな感じでいいのでしょうか?
ageはint型なのでどのようにしたら?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# c言語の問題の説明、各所ごとに 5 2023/07/26 11:03
- C言語・C++・C# c言語の問題です 2 2023/07/21 10:51
- C言語・C++・C# C言語初心者 構造体 課題について 1 2023/03/10 19:30
- C言語・C++・C# 100バイトのバイナリファイルを読み込んで別のファイルに書き込みたいのですが、型をどうすればいいのか 1 2022/11/03 17:11
- C言語・C++・C# このプログラミング誰か教えてくれませんか 1 2022/06/02 15:27
- C言語・C++・C# C言語初心者 構造体 課題について 2 2023/03/10 19:48
- C言語・C++・C# プログラムが書けません。 4 2023/01/22 22:57
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
- C言語・C++・C# C++プログラミングコードにポリモーフィズムを取り入れ方を教えてください。 2 2023/06/09 11:17
- Perl Perlで特定文字列から特定文字列までを抜き出したい 4 2022/04/02 14:24
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
nullと""、\\0とEOFの違いにつ...
-
[C++]WCHARの1文字目しか表示で...
-
C#でstringをポインタとして渡す
-
プログラムによく出てくるst...
-
[C#.net]正規表現による指定文...
-
WSH(VBS)でJSONの文字列を読み...
-
ソースコードの間違い (C言語)
-
C++で入力した文字列から数字を...
-
ASPで別サイトの内容を Stream ...
-
c#で他のアプリの文字入力フォ...
-
セグメントエラー
-
関数から配列を返すには?
-
VBAのプログラムで、DIAG = 1# ...
-
ExcelVBAで質問です。離れた二...
-
配列を使わずに、変数名を動的...
-
VC++6.0 MFC ダイアログバーを...
-
Integer変数をカラにしたいので...
-
先頭アドレスとは何ですか?
-
Run-Time Check Failure #3とい...
-
C言語で特定列だけを抽出して配...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C++で入力した文字列から数字を...
-
nullと""、\\0とEOFの違いにつ...
-
プログラムによく出てくるst...
-
%dなどの違い
-
WSH(VBS)でJSONの文字列を読み...
-
TCL言語で文字列検索方法を教え...
-
C#でstringをポインタとして渡す
-
16進数を2文字ずつ配列に格納し...
-
_tcscpy_s(wcscpy_s)の第二引数...
-
C++で文字列の右端から特定の文...
-
シリアル通信で0x00を送信した...
-
VBA-DLLの引数受け渡しについて
-
数字の入った配列をファイルへ...
-
c#で他のアプリの文字入力フォ...
-
構造体→文字列→構造体 をする方法
-
Shift_JIS(16進)を文字に変換す...
-
バイナリファイル中の日本語文...
-
C言語の課題で困っています;
-
[C++]WCHARの1文字目しか表示で...
-
VB6.0でのバイナリデータの扱い...
おすすめ情報