質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

Q&A

解決済

3回答

250閲覧

C言語の文字列の処理について

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

ポインタ

ポインタはアドレスを用いてメモリに格納された値を"参照する"変数です。

0グッド

0クリップ

投稿2018/08/01 16:02

C言語の文字の扱いについてわからないことがあるため質問させてもらいます。
txtファイルに以下のような文字列が入っているとします。

test.txt

1Apple 1 2 3 4 2Orange 2 4 6 8 3Lemon 3 6 9 12

このテキストファイルはスペース区切りで名前、数字4つのように構成されています。
プログラムで扱いやすいように以下のような構造体を定義しました。

C

1struct list{ 2 char* name; 3 int num[4]; 4}; 5typedef struct list *listp;

この構造体のポインターの配列を用意してそこにtest.txtから読み込んだ値を入れていきたいのですが、うまくいきません。
プログラムは以下のようです。

C

1#include <stdio.h> 2#include <string.h> 3 4struct list{ 5 char* name; 6 int num[4]; 7}; 8typedef struct list *listp; 9 10int main(int argc, const char * argv[]) { 11 FILE *fp; 12 char *fname = "test.txt"; 13 char s[100]; 14 char *ptr; 15 int i = 0, j = 0; 16 listp item[3]; 17 18 fp = fopen(fname, "r" ); 19 while(fgets(s, 100, fp) != NULL){ 20 ptr = strtok(s, " "); 21 item[i]->name = ptr; 22 while(ptr != NULL) { 23 ptr = strtok(NULL, " "); 24 if(ptr != NULL) { 25 item[i]->num[j] = *ptr; 26 j += 1; 27 } 28 } 29 i += 1; 30 }

とりあえずfgetsでtxtを一行ずつ読み取って、strtokで文字列を分割して処理しているのですが、エラーが出てしまいます。ptrはcharのポインターなので代入するだけではダメだと思うのですが、具体的にどのようにしたら良いのかわかりません。構造体もこれでいいのかよくわかりません。とりあえずtxtをいい感じにプログラムで扱えるようにしたいです。プログラムの間違いや、根本的にこのようなtxtを扱うのに良いやり方があればお教えください。よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

listp item[3];の各要素はポインタなので、item[i]->name = ~;とその先に代入しようとしても、その先には何もありません。
使用に先立って、item[i]=(listp)malloc(sizeof(struct list));などと、ポインターにその指す変数用領域アドレスの代入が必要です。

また、item[i]->name = ptr;と、s[100]の中のアドレスを代入していますが、s[100]は1行毎に上書きされるので、次の行を読むとそのアドレスに書かれている文字は変わってしまいます。

num[j]に文字を代入していますが、やりたいのは文字列を十進数とみなしてintにしてその値を代入することでしょうから、atoi()等が必要です。

ざっとみて気づいた物を書きましたが、もっと他にも間違いがあるかと思います。

ポインタについての理解はあるようですが、ポインタの使い方の理解が全く出来ていませんので、もっと簡単なプログラムから始めるのが良いと思います。

投稿2018/08/01 16:17

otn

総合スコア84507

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/08/01 16:56

ご回答ありがとうございます。あまりC言語を書かないのでだいぶ苦労しています。 >また、item[i]->name = ptr;と、s[100]の中のアドレスを代入していますが、s[100]は1行毎に上書きされるので、次の行を読むとそのアドレスに書かれている文字は変わってしまいます。 この問題を回避するには構造体のnameをポインター変数ではなく、普通の変数にしてstrcpyを使えば解消できるでしょうか?
otn

2018/08/01 23:38

> この問題を回避するには構造体のnameをポインター変数ではなく、普通の変数にしてstrcpyを使えば解消できるでしょうか? それもありですね。配列サイズを決められるのなら、それが簡単です。
otn

2018/08/02 00:05

listp item[3]; についても同様。 struct list item[3]; なら各要素がポインタじゃなくて構造体そのものになるので、item[i].num[j] = ~ とかすればいい。
guest

0

裏技ですがこんな方法もあります。

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4typedef struct{ 5 int num[4]; 6 char name[1]; 7} *listp; 8 9/* 10 戻り値 作成したlist構造体へのポインタ 呼び出した側が責任持ってfreeすること 11 */ 12listp createList(const char* name, int num1, int num2, int num3, int num4){ 13 size_t len = strlen(name); 14 listp result = malloc(sizeof(listp[0]) + len); 15 result->num[0] = num1; 16 result->num[1] = num2; 17 result->num[2] = num3; 18 result->num[3] = num4; 19 strcpy(result->name, name); 20 return result; 21} 22/* 23 戻り値 作成したlist構造体へのポインタ 呼び出した側が責任持ってfreeすること 24 */ 25listp createListFromString(const char* str){ 26 char name[100] = {}; 27 int num1, num2, num3, num4; 28 sscanf(str,"%99s %d %d %d %d", name, &num1, &num2, &num3, &num4); 29 return createList(name, num1, num2,num3,num4); 30} 31 32int main(){ 33 listp p = createList("test", 10, 200, 3000, 4); 34 printf("[%s]: [%d] [%d] [%d] [%d]\n", p->name, p->num[0], p->num[1], 35 p->num[2], p->num[3]); 36 free(p); 37 p = createListFromString("test2 1 2 3 4"); 38 printf("[%s]: [%d] [%d] [%d] [%d]\n", p->name, p->num[0], p->num[1], 39 p->num[2], p->num[3]); 40 free(p); 41 return 0; 42}

投稿2018/08/02 02:06

asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/08/02 10:15

回答有り難うございます。 無事解決できました。
guest

0

たぶん何かの課題だと思われますが、動的メモリを使うという問題でないのであれば、構造体の定義を見直すべきでしょう。
現在の定義はnameがポインタになっております。
ポインタはあくまでもどこかの領域のアドレス値を持つだけで、今の作りのように変数sの一部のアドレスを格納しても、領域は常に同じなため意味がありません。
nameはポインタはなく実体としましょう。

c

1struct list{ 2 char name[16]; 3 int num[4]; 4};

サイズは仮に16バイト(15文字+NULL文字)としていますが、文字数の上限の決まりがあるならそれにあわせてください。
あとはstrtokで切り出したあたいをコピーすればよいでしょう。

c

1strcpy(item[i]->name, ptr);

ただし、numに関してはint型なので数値に変換する必要があります。
atoi関数あたりを使うのが妥当です。

c

1item[i]->num[0] = atoi(ptr);

投稿2018/08/02 00:30

ttyp03

総合スコア16998

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/08/02 10:15

回答有り難うございます。 無事解決できました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問