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

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

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

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

Q&A

解決済

4回答

308閲覧

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

RaitoN

総合スコア72

C

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

1グッド

0クリップ

投稿2019/02/22 13:57

###次のようなプログラムを書きたいのですが,どのように処理をしていけばいいのか方針が立ちません

作りたいプログラム
化学式を入力して,その分子量を返すプログラム

原子量
H:1
C:12
O:16

例1
(入力) CO2
(出力) 44
// 12+16*2=44

例2
(入力) (CH3)2CO
(出力) 58
// 123+16+16=58

例3
(入力) CH(C0.8H0.2)2O
(出力) 48.6
// 122.6+11.4+16=48.6

入力する文字列に小数がない場合はみなさんの知恵を貸していただいて,次のようにして解決したのですが小数があると難しいです.

整数のみの場合(例2)
先に文字列を展開して整理
(CH3)2CO -> (CHHH)2CO -> CHHHCHHHCO -> CCC HHHHHH O -> 123+16+16=58

(例3)のように小数が混じると別の方法で処理をしないといけなく,難しいです.

括弧の中の文字列抜き出して括弧の後ろの数値がいくつなのか判断して...まで書いたのですが今後の方針が立たず困っています.

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5// CGS-EMU 6#define BOHR_MAGNETON 9.274009994E-21 7#define AVOGADRO_CONSTANT 6.022140857E23 8 9void Get_Sample_Name(char samplename[128]) { 10 11 puts("Enter the chemical formula of the sample."); 12 printf("Chemical formula : "); 13 scanf("%s", samplename); 14 15 return; 16 17} 18 19void Molecular_Weight(char samplename[128]) { 20 21 char buf[128] = {}, chem_form[128] = {}, inBK[64] = {}; 22 char *bra, *ket; 23 int i, j; 24 int start, end, len, cnt = 0; 25 double sub[32] = {}, subBK[16] = {}; 26 double ketnum; 27 28 bra = strchr(samplename, '('); 29 ket = strchr(samplename, ')'); 30 31 if (bra == NULL && ket == NULL) { 32// No Bracket 33 strcpy(chem_form, samplename); 34 } else if (bra == NULL && ket != NULL) { 35 puts("Not exist '('"); 36 exit(0); 37 } else if (bra != NULL && ket == NULL) { 38 puts("Not exist ')'"); 39 exit(0); 40 } else { 41// Brackets 42 len = (int)strlen(samplename); 43 // printf("len:%d\n", len); 44 // printf("No:%d\n", (int)(ket - samplename)); 45 start = (int)(bra - samplename); 46 end = (int)(ket - samplename); 47 // printf("start:%d\nend:%d\n", start, end); 48 49// Extract values after brackets. 50 j = end; 51 for (i=0; i<len-end; i++) { 52 j++; 53 buf[i] = samplename[j]; 54 } 55 ketnum = atof(buf); 56 57 for (i=0; i<128; i++) { 58 buf[i] = '\0'; 59 } 60 61 j = start + 1; 62 for(i=0; i<end-start-1; i++) { 63 inBK[i] = samplename[j]; 64 j++; 65 } 66 67 printf("inBK:%s\n", inBK); 68 // printf("buf:%s\n", buf); 69 // printf("no:%lf\n", ketnum); 70 if (ketnum == 0) { 71 j = 0; 72 for (i=0; i<len; i++) { 73 if ((samplename[i] == '(') || (samplename[i] == ')')) { 74 } else { 75 chem_form[j] = samplename[i]; 76 j++; 77 } 78 } 79 } else { 80 81 i = 0; 82 j = 0; 83 while (inBK[i] != '\0') { 84 // puts("ss"); 85 if (inBK[i] >= '0' && inBK[i] <= '9') { 86 printf("i:%d\n", i); 87 } 88 i++; 89 } 90 91 92 } 93 94 95 96 } 97 98 printf("chemform:%s\n", chem_form); 99 100 101 return; 102} 103 104 105int main(int argc, const char * argv[]) { 106 107 char samplename[128] = {}; 108 109 Get_Sample_Name(samplename); 110 Molecular_Weight(samplename); 111 112 return 0; 113} 114
DrqYuto👍を押しています

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

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

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

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

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

wwbQzhMkhhgEmhU

2019/02/22 23:13

この手の問題は、一般的にはパースツリーを作った後、それをトラバースして評価します。 toshi17922062さんのおっしゃる方法ですね。ただ、これは少し考え方が難しい?ので、いろいろ出来るようになってから勉強した方がいいかもしれません。 最初からそんなに綺麗に書けるようになる必要もないので、まずは R.nkmrさんが出来ることに近いところからやるのが妥当だと思います。そういう意味では、いろいろ合わせてくれた、jimbeさんの回答が一番参考になると思います。
guest

回答4

0

回答ではなくあくまで参考意見なのですが、本来このような構文解析は分木を使うのではないかと思います。

私も昔逆ポーランドのサンプルを作った程度で、そこまで詳しいわけではないので参考になるかどうかわかりませんが参考サイトを提示しておきます。まったく的外れでしたらすいません。

数式の二分木化・記法変換・計算 (C#) - Programming/Tips/二分木を使った数式の逆ポーランド記法化と計算 - 総武ソフトウェア推進所

サンプルケースの二分木イメージ(違うかもですが)

imege

1 2(入力)CO2 3+-- 4| | 5C *- 6 | | 7 O 2 8 9(入力)(CH3)2CO 10+------ 11| | 12*---- +-- 13| | | | 14+-- 2 C O 15| | 16C *- 17 | | 18 H 3 19 20 21(入力) CH(C0.8H0.2)2O 22+----- 23| | 24+- O 25| | 26C +- 27 | | 28 H *-------------- 29 | | 30 +------ 2 31 | | 32 *-- *-- 33 | | | | 34 C 0.8 H 0.2 35 36

ついでの先にリンクしたサイトのpythonバージョンでの実行結果を載せておきます。
CHOをそれぞれ数値化して、式に+*を明示して()もそのまま入力しました。

input expression: expression: 12+16*2 reverse polish notation: 12 16 2 * + infix notation: (12 + (16 * 2)) polish notation: + 12 * 16 2 calculated result: 44 input expression: expression: (12+1*3)*2+12+16 reverse polish notation: 12 1 3 * + 2 * 12 + 16 + infix notation: ((((12 + (1 * 3)) * 2) + 12) + 16) polish notation: + + * + 12 * 1 3 2 12 16 calculated result: 58 input expression: expression: 12+1+(12*0.8+1*0.2)*2+16 reverse polish notation: 12 1 + 12 0.8 * 1 0.2 * + 2 * + 16 + infix notation: (((12 + 1) + (((12 * 0.8) + (1 * 0.2)) * 2)) + 16) polish notation: + + + 12 1 * + * 12 0.8 * 1 0.2 2 16 calculated result: 48.6

おまけ。
ついでに二分木なしのをpythonの勉強がてら作ってみました。まだバグあると思いますが。
pythonいいですよ。

python

1 2atom={ 3'H':1, 4'C':12, 5'O':16, 6'Cl':17, 7'Co':27 8} 9 10def is_num(s): 11 return s.replace(',', '').replace('.', '').replace('-', '').isnumeric() 12 13def chmicalc(cf): 14 cflist=list(cf) #リスト化する 15 cftemp=[] 16 for temp in cflist: 17 if temp in ['(',')']: 18 #1.括弧'('or')'のケース 19 if (not len(cftemp)==0) and cftemp[-1].isalpha() and temp=='(': 20 #最初ではない、'('かつリスト最後が文字のとき:'+'をappend後、tempをappend 21 cftemp.append('+') 22 cftemp.append(temp) 23 else: 24 #それ以外の括弧:tempをappend 25 cftemp.append(temp) 26 elif temp.isalpha(): 27 #2.文字(元素記号)のケース: 28 if temp==temp.upper(): 29 #大文字のケース: 30 if (not len(cftemp)==0) and (is_num(cftemp[-1]) or cftemp[-1].isalpha()): 31 #最初ではない、かつリスト最後が文字か数字なら'+'をappend後、tempをappend 32 cftemp.append('+') 33 cftemp.append(temp) 34 else: 35 #それ以外の文字:tempをappend 36 cftemp.append(temp) 37 else: 38 #小文字のケース:cftempの最後の文字に追加 39 cftemp[-1]+=temp 40 elif temp.isnumeric(): 41 #3.数字のケース 42 if cftemp[-1]==')': 43 #リスト最後の文字が')':'*'をappend後、tempをappend 44 cftemp.append('*') 45 cftemp.append(temp) 46 elif (is_num(cftemp[-1])): 47 #リスト最後が数字:cftempの最後の文字に追加 48 cftemp[-1]+=temp 49 elif (not cftemp[-1].find('.')==-1): 50 #リスト最後がピリオド:cftempの最後の文字に追加 51 cftemp[-1]+=temp 52 else: 53 #それ以外の数字:'*'をappend後、tempをappend 54 cftemp.append('*') 55 cftemp.append(temp) 56 elif temp=='.': 57 #4.ピリオドのケース:cftempの最後の文字に追加 58 cftemp[-1]+=temp 59 60 compleatcf='' 61 for temp in cftemp: 62 if temp.isalpha(): 63 compleatcf+=str(atom[temp]) #元素記号の数値化 64 else: 65 compleatcf+=temp 66 67 print('元の化学式:cf:{}'.format(cf)) 68 print('テンポラリ:cftemp:{}'.format(cftemp)) 69 print('compleatcf:{}'.format(compleatcf)) 70 print('eval(compleatcf):{}'.format(eval(compleatcf))) 71 72 73 74#CO2 75chmicalc('CO2') 76 77#(CH3)2CO 78chmicalc('(CH3)2CO') 79 80#CH(C0.8H0.2)2O 81chmicalc('CH(C0.8H0.2)2O') 82 83#CH3CH2OH 84chmicalc('CH3CH2OH') 85 86#CoCl2 87chmicalc('CoCl2') 88
元の化学式:cf:CO2 テンポラリ:cftemp:['C', '+', 'O', '*', '2'] compleatcf:12+16*2 eval(compleatcf):44 元の化学式:cf:(CH3)2CO テンポラリ:cftemp:['(', 'C', '+', 'H', '*', '3', ')', '*', '2', '+', 'C', '+', 'O'] compleatcf:(12+1*3)*2+12+16 eval(compleatcf):58 元の化学式:cf:CH(C0.8H0.2)2O テンポラリ:cftemp:['C', '+', 'H', '+', '(', 'C', '*', '0.8', '+', 'H', '*', '0.2', ')', '*', '2', '+', 'O'] compleatcf:12+1+(12*0.8+1*0.2)*2+16 eval(compleatcf):48.6 元の化学式:cf:CH3CH2OH テンポラリ:cftemp:['C', '+', 'H', '*', '3', '+', 'C', '+', 'H', '*', '2', '+', 'O', '+', 'H'] compleatcf:12+1*3+12+1*2+16+1 eval(compleatcf):46 元の化学式:cf:CoCl2 テンポラリ:cftemp:['Co', '+', 'Cl', '*', '2'] compleatcf:27+17*2 eval(compleatcf):61

投稿2019/02/22 15:51

編集2019/02/23 15:10
toshi17922062

総合スコア183

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

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

RaitoN

2019/02/23 00:41

このようなアルゴリズムは知りませんでした.ありがとうございます.参考にします.
guest

0

回答までたどり着いていませんが、、、

以下のような構造体を使って構文解析する必要があるのではと思います。

C

1struct Atom { 2 int AtomName; // 原子 (二文字もあるので、char 一文字は無理) 3 struct Atom *moles; // 分子(?) AtomName とどちらか有効とする 4 double weight; // 重さ 5 int unit; // 原子または、分子の数 6}

上記の構造体で十分かは、未確認ですが、こんな感じで、作れば、なんとかなりそうという事で、参考までに。

投稿2019/02/22 15:00

pepperleaf

総合スコア6383

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

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

RaitoN

2019/02/23 00:41

回答ありがとうございます.
guest

0

ベストアンサー

少数点以下一桁~二桁程度でしたら, 計算を全て 100 倍で行って, 最後に 1/100 にするのは如何でしょうか.

java で書いたものを移植する形で書いてみました.
メモリの大きさ等あちこち危ない作りですので, あまり長い式を計算しようとすると落ちると思います.
数値の取り出し部分では, 少数点が複数ある等の異常状態も無視しております.

式の内部表現は以下のようなイメージになります.
CH(C0.8H0.2)2O のイメージ図

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5typedef struct Material { 6 int type; //0=Atom, 1=Molecule 7} Material_t; 8 9typedef struct Atom { 10 int material_type; //0=Atom, 1=Molecule 11 char name[4]; //2文字+'\0' 12 int weight; 13} Atom_t; 14Atom_t atoms[] = { 15 { 0, "H", 1 }, 16 { 0, "C", 12 }, 17 { 0, "O", 16 }, 18 {-1, "", -1 } //EOD 19}; 20Atom_t *search_atom(char *name) { 21 Atom_t *p; 22 for(p=atoms; p->weight>0; p++) { 23 if(strcmp(p->name, name) == 0) return p; 24 } 25 return NULL; //無し 26} 27 28typedef struct MaterialValue { 29 Material_t *material; //Atom or Molecule 30 double ratio; 31} MaterialValue_t; 32 33typedef struct Molecule { 34 int material_type; //0=Atom, 1=Molecule 35 int materials_count; 36 MaterialValue_t materials[16]; //大きさはテキトウ 37} Molecule_t; 38Molecule_t *newMolecule() { 39 Molecule_t *molecule = (Molecule_t *)malloc(sizeof(Molecule_t)); 40 molecule->material_type = 1; 41 molecule->materials_count = 0; 42 return molecule; 43} 44void add(Molecule_t *molecule, Material_t *material) { 45 MaterialValue_t *mv = &(molecule->materials[molecule->materials_count++]); 46 mv->material = material; 47 mv->ratio = 1.0; 48} 49void setRatio(Molecule_t *molecule, double ratio) { 50 molecule->materials[molecule->materials_count-1].ratio = ratio; 51} 52double getWeight(Molecule_t *molecule) { 53 int i; 54 double weight = 0; 55 for(i=0; i<molecule->materials_count; i++) { 56 MaterialValue_t *mv = &molecule->materials[i]; 57 if(mv->material->type == 0) { //Atom 58 weight += ((Atom_t *)(mv->material))->weight * mv->ratio; 59 } else { //Molecule 60 weight += getWeight((Molecule_t *)(mv->material)) * mv->ratio; 61 } 62 } 63 return weight; 64} 65 66 67//スタック 68Molecule_t *stack[16]; //大きさはテキトウ 69int stack_pointer = 0; 70void stack_push(Molecule_t *molecule) { 71 stack[stack_pointer++] = molecule; 72} 73Molecule_t *stack_pop() { 74 return stack[--stack_pointer]; 75} 76Molecule_t *stack_peek() { 77 return stack[stack_pointer-1]; 78} 79 80//解析 81int isDigit(char c) { 82 return ('0' <= c && c <= '9'); 83} 84int isDigitOrPeriod(char c) { 85 return (isDigit(c) || c == '.'); 86} 87Molecule_t *parse(char *samplename) { 88 int i, j, k; 89 char v[16]; //大きさはテキトウ 90 stack_push(newMolecule()); 91 for(i=0; i<strlen(samplename); i++) { 92 memset(v, 0, sizeof(v)); 93 v[0] = samplename[i]; 94 if(isDigit(v[0])) { 95 for(j=i+1, k=1; j<strlen(samplename) && isDigitOrPeriod(samplename[j]); k++, j++, i++) { 96 v[k] = samplename[j]; 97 } 98 setRatio(stack_peek(), atof(v)); 99 } else if(strcmp(v, "(") == 0) { 100 stack_push(newMolecule()); 101 } else if(strcmp(v, ")") == 0) { 102 Material_t *material = (Material_t *)stack_pop(); 103 add(stack_peek(), material); 104 } else { 105 add(stack_peek(), (Material_t *)search_atom(v)); 106 } 107 } 108 return stack_pop(); 109} 110 111int main(int argc, char *argv[]) { 112 printf("CO2=%f\n", getWeight(parse("CO2"))); 113 printf("(CH3)2CO=%f\n", getWeight(parse("(CH3)2CO"))); 114 printf("CH(C0.8H0.2)2O=%f\n", getWeight(parse("CH(C0.8H0.2)2O"))); 115 return 0; 116}

投稿2019/02/22 15:00

編集2019/02/23 05:35
jimbe

総合スコア12646

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

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

RaitoN

2019/02/23 00:40

ありがとうございます. 大変参考になりました.頑張って勉強していきたいと思います.
RaitoN

2019/02/23 07:28

わかりやすい図まで本当にありがとうございます. 疑問があるのですが,例えばHeを含む(実際は化合物を作りませんが)ようなものを仮定して,入力に(CHHe)とした時エラーが出てしまいませんか? search_atom関数の中でstrcmpで文字列を比較していますが,parse関数の中でのchar型配列v[16]の文字を1文字ずつ処理しているのでどうしても2文字の原子にはこれだと対応していないと思ったのですが,どうなのでしょうか...?
jimbe

2019/02/23 07:40

はい、このコードでは 2 文字以上の元素には対応しておりません. parse での文字列処理を2文字以上が可能なように修正する必要がございます. for 文の中の if 文で, 数字の場合に別途ループして全数字(とピリオド)を取得していますように, 最後の else の中で 'v に一致する atom が無かった(=search_atom が NULL だった)ら, v に一文字を追加してまた探す' ようなループ処理を入れてみるのも一案かと思います.
RaitoN

2019/02/23 07:51

回答ありがとうございます.そうですね.確かにそのような処理で対応できそうですね. NとNb, HとHe, BとBeのように先頭が同じ文字の原子もあるので完全に対応するのは,もう少し追加の処理が必要だと思いますが,なんとか頑張ってやってみようと思います.
jimbe

2019/02/23 08:05

なるほど, やはり同じ先頭文字が複数あるのですね. 原子の2文字目が **必ず小文字** であって, 小文字が **1文字目には無い** とすれば, else に入った所で samplename[i+1] を調べ, アルファベットの小文字であれば v[1] に設定して(i++も行って) search_atom に入れても良いかもしれません.
RaitoN

2019/02/23 09:29

なるほど!解決できました. 単純にelse文の中に追加しただけだとSegmentation fault: 11とエラーが出てしまったのですが,parse関数のv[16]の初期化をすることで解決できました. ありがとうございます! ```C #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct Material { int type; //0=Atom, 1=Molecule } Material_t; typedef struct Atom { int material_type; //0=Atom, 1=Molecule char name[4]; //2文字+'\0' int weight; } Atom_t; Atom_t atoms[] = { { 0, "H", 1 }, { 0, "He", 4 }, { 0, "Li", 7 }, { 0, "C", 12 }, { 0, "O", 16 }, {-1, "", -1 } //EOD }; Atom_t *search_atom(char *name) { Atom_t *p; for(p=atoms; p->weight>0; p++) { if(strcmp(p->name, name) == 0) return p; } return NULL; //無し } typedef struct MaterialValue { Material_t *material; //Atom or Molecule double ratio; } MaterialValue_t; typedef struct Molecule { int material_type; //0=Atom, 1=Molecule int materials_count; MaterialValue_t materials[16]; //大きさはテキトウ } Molecule_t; Molecule_t *newMolecule() { Molecule_t *molecule = (Molecule_t *)malloc(sizeof(Molecule_t)); molecule->material_type = 1; molecule->materials_count = 0; return molecule; } void add(Molecule_t *molecule, Material_t *material) { MaterialValue_t *mv = &(molecule->materials[molecule->materials_count++]); mv->material = material; mv->ratio = 1.0; } void setRatio(Molecule_t *molecule, double ratio) { molecule->materials[molecule->materials_count-1].ratio = ratio; } double getWeight(Molecule_t *molecule) { int i; double weight = 0; for(i=0; i<molecule->materials_count; i++) { MaterialValue_t *mv = &molecule->materials[i]; if(mv->material->type == 0) { //Atom weight += ((Atom_t *)(mv->material))->weight * mv->ratio; } else { //Molecule weight += getWeight((Molecule_t *)(mv->material)) * mv->ratio; } } return weight; } //Stack Molecule_t *stack[16]; //大きさはテキトウ int stack_pointer = 0; void stack_push(Molecule_t *molecule) { stack[stack_pointer++] = molecule; } Molecule_t *stack_pop() { return stack[--stack_pointer]; } Molecule_t *stack_peek() { return stack[stack_pointer-1]; } //Analysis int isDigit(char c) { return ('0' <= c && c <= '9'); } int isDigitOrPeriod(char c) { return (isDigit(c) || c == '.'); } Molecule_t *parse(char *samplename) { int i, j, k; char v[16] = {}; //大きさはテキトウ stack_push(newMolecule()); for(i=0; i<strlen(samplename); i++) { memset(v, 0, sizeof(v)); v[0] = samplename[i]; if(isDigit(v[0])) { for(j=i+1, k=1; j<strlen(samplename) && isDigitOrPeriod(samplename[j]); k++, j++, i++) { v[k] = samplename[j]; } setRatio(stack_peek(), atof(v)); } else if(strcmp(v, "(") == 0) { stack_push(newMolecule()); } else if(strcmp(v, ")") == 0) { Material_t *material = (Material_t *)stack_pop(); add(stack_peek(), material); } else { if ((samplename[i+1]>='a') && (samplename[i+1]<='z')) { v[1] = samplename[i+1]; i++; } add(stack_peek(), (Material_t *)search_atom(v)); } } return stack_pop(); } int main(int argc, char *argv[]) { printf("CHHe=%f\n", getWeight(parse("CHHe"))); printf("(CH3)2CO=%f\n", getWeight(parse("(CH3)2CO"))); printf("CH(C0.8H0.2)2O=%f\n", getWeight(parse("CH(C0.8H0.2)2O"))); return 0; } ```
jimbe

2019/02/23 10:57

segfault が発生しましたか. i は strlen(samplename) までで回していますので, else で samplename[i+1] にアクセスしても, 最後は '\0' になると思ったのですが. v は for ループの始めに memset で 0 クリアしていますので, 初期化の効果は分かりません. どちらも処理系の違いでしょうか. 私はCの環境が手元にありませんでしたので, 以下のサイトで実行致しました. http://www.tutorialspoint.com/compile_c_online.php
guest

0

みなさまありがとうございました.無事解決しました.

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5 6typedef struct Material { 7 int type; //0=Atom, 1=Molecule 8} Material_t; 9 10typedef struct Atom { 11 int material_type; //0=Atom, 1=Molecule 12 char name[4]; 13 double weight; 14} Atom_t; 15 16Atom_t atoms[] = { 17 { 0, "H" , 1.00798 }, 18 { 0, "He", 4.0026 }, 19 { 0, "Li", 6.968 }, 20 { 0, "Be", 9.01218 }, 21 { 0, "B" , 10.814 }, 22 { 0, "C" , 12.0106 }, 23 { 0, "N" , 14.0069 }, 24 { 0, "O" , 15.9994 }, 25 { 0, "F" , 18.9984 }, 26 { 0, "Ne", 20.1797 }, 27 { 0, "Na", 22.9898 }, 28 { 0, "Mg", 24.306 }, 29 { 0, "Al", 26.9815 }, 30 { 0, "Si", 28.085 }, 31 { 0, "P" , 30.9738 }, 32 { 0, "S" , 32.068 }, 33 { 0, "Cl", 35.452 }, 34 { 0, "Ar", 39.948 }, 35 { 0, "K" , 39.0983 }, 36 { 0, "Ca", 40.078 }, 37 { 0, "Sc", 44.9559 }, 38 { 0, "Ti", 47.867 }, 39 { 0, "V" , 50.9415 }, 40 { 0, "Cr", 51.9961 }, 41 { 0, "Mn", 54.938 }, 42 { 0, "Fe", 55.845 }, 43 { 0, "Co", 58.9332 }, 44 { 0, "Ni", 58.6934 }, 45 { 0, "Cu", 63.546 }, 46 { 0, "Zn", 65.38 }, 47 { 0, "Ga", 69.723 }, 48 { 0, "Ge", 72.630 }, 49 { 0, "As", 74.9216 }, 50 { 0, "Se", 78.971 }, 51 { 0, "Br", 79.904 }, 52 { 0, "Kr", 83.798 }, 53 { 0, "Rb", 85.4678 }, 54 { 0, "Sr", 87.62 }, 55 { 0, "Y" , 88.9058 }, 56 { 0, "Zr", 91.224 }, 57 { 0, "Nb", 92.9064 }, 58 { 0, "Mo", 95.95 }, 59 { 0, "Tc", 99 }, 60 { 0, "Ru", 101.07 }, 61 { 0, "Rh", 102.906 }, 62 { 0, "Pd", 106.42 }, 63 { 0, "Ag", 107.868 }, 64 { 0, "Cd", 112.414 }, 65 { 0, "In", 114.818 }, 66 { 0, "Sn", 118.710 }, 67 { 0, "Sb", 121.760 }, 68 { 0, "Te", 127.60 }, 69 { 0, "I" , 126.904 }, 70 { 0, "Xe", 131.293 }, 71 { 0, "Cs", 132.905 }, 72 { 0, "Ba", 137.327 }, 73 { 0, "La", 138.905 }, 74 { 0, "Ce", 140.116 }, 75 { 0, "Pr", 140.908 }, 76 { 0, "Nd", 144.242 }, 77 { 0, "Pm", 145 }, 78 { 0, "Sm", 150.36 }, 79 { 0, "Eu", 151.964 }, 80 { 0, "Gd", 157.25 }, 81 { 0, "Tb", 158.925 }, 82 { 0, "Dy", 162.500 }, 83 { 0, "Ho", 164.930 }, 84 { 0, "Er", 167.259 }, 85 { 0, "Tm", 168.934 }, 86 { 0, "Yb", 173.045 }, 87 { 0, "Lu", 174.967 }, 88 { 0, "Hf", 178.49 }, 89 { 0, "Ta", 180.948 }, 90 { 0, "W" , 183.84 }, 91 { 0, "Re", 186.207 }, 92 { 0, "Os", 190.23 }, 93 { 0, "Ir", 192.217 }, 94 { 0, "Pt", 195.084 }, 95 { 0, "Au", 196.967 }, 96 { 0, "Hg", 200.592 }, 97 { 0, "Tl", 204.384 }, 98 { 0, "Pb", 207.2 }, 99 { 0, "Bi", 208.980 }, 100 { 0, "Po", 210 }, 101 { 0, "At", 210 }, 102 { 0, "Rn", 222 }, 103 { 0, "Fr", 223 }, 104 { 0, "Ra", 226 }, 105 { 0, "Ac", 227 }, 106 { 0, "Th", 232.038 }, 107 { 0, "Pa", 231.036 }, 108 { 0, "U" , 238.029 }, 109 { 0, "Np", 237 }, 110 { 0, "Pu", 239 }, 111 { 0, "Am", 243 }, 112 { 0, "Cm", 247 }, 113 { 0, "Bk", 247 }, 114 { 0, "Cf", 252 }, 115 { 0, "Es", 252 }, 116 { 0, "Fm", 257 }, 117 { 0, "Md", 258 }, 118 { 0, "No", 259 }, 119 { 0, "Lr", 262 }, 120 { 0, "Rf", 267 }, 121 { 0, "Db", 268 }, 122 { 0, "Sg", 271 }, 123 { 0, "Bh", 272 }, 124 { 0, "Hs", 277 }, 125 { 0, "Mt", 276 }, 126 { 0, "Ds", 281 }, 127 { 0, "Rg", 280 }, 128 { 0, "Cn", 285 }, 129 { 0, "Nh", 278 }, 130 { 0, "Fl", 289 }, 131 { 0, "Mc", 289 }, 132 { 0, "Lv", 293 }, 133 { 0, "Ts", 293 }, 134 { 0, "Og", 294 }, 135 {-1, "", -1 } //EOD 136}; 137 138Atom_t *search_atom(char *name) { 139 Atom_t *p; 140 for (p=atoms; p->weight>0; p++) { 141 if (strcmp(p->name, name) == 0) return p; 142 } 143 144 exit(0); 145 return NULL; //Not exist 146} 147 148typedef struct MaterialValue { 149 Material_t *material; //Atom or Molecule 150 double ratio; 151} MaterialValue_t; 152 153typedef struct Molecule { 154 int material_type; //0=Atom, 1=Molecule 155 int materials_count; 156 MaterialValue_t materials[64]; 157} Molecule_t; 158 159Molecule_t *newMolecule() { 160 Molecule_t *molecule = (Molecule_t *)malloc(sizeof(Molecule_t)); 161 molecule->material_type = 1; 162 molecule->materials_count = 0; 163 return molecule; 164} 165 166void add(Molecule_t *molecule, Material_t *material) { 167 MaterialValue_t *mv = &(molecule->materials[molecule->materials_count++]); 168 mv->material = material; 169 mv->ratio = 1.0; 170} 171 172void setRatio(Molecule_t *molecule, double ratio) { 173 molecule->materials[molecule->materials_count-1].ratio = ratio; 174} 175 176double getWeight(Molecule_t *molecule) { 177 int i; 178 double weight = 0; 179 for(i=0; i<molecule->materials_count; i++) { 180 MaterialValue_t *mv = &molecule->materials[i]; 181 if(mv->material->type == 0) { //Atom 182 weight += ((Atom_t *)(mv->material))->weight * mv->ratio; 183 } else { //Molecule 184 weight += getWeight((Molecule_t *)(mv->material)) * mv->ratio; 185 } 186 } 187 return weight; 188} 189 190//Stack 191Molecule_t *stack[64]; 192int stack_pointer = 0; 193void stack_push(Molecule_t *molecule) { 194 stack[stack_pointer++] = molecule; 195} 196Molecule_t *stack_pop() { 197 return stack[--stack_pointer]; 198} 199Molecule_t *stack_peek() { 200 return stack[stack_pointer-1]; 201} 202 203//Analysis 204int isDigit(char c) { 205 return ('0' <= c && c <= '9'); 206} 207int isDigitOrPeriod(char c) { 208 return (isDigit(c) || c == '.'); 209} 210void JudgeBrackets(char samplename[64]) { 211 212 char *bra, *ket; 213 int start, end; 214 215 bra = strchr(samplename, '('); 216 ket = strchr(samplename, ')'); 217 218 if ((bra == NULL) && (ket == NULL)) { 219 // Not exist brackets 220 return; 221 } else if ((bra == NULL) && (ket != NULL)) { 222 puts("Not exist '('"); 223 exit(0); 224 } else if ((bra != NULL) && (ket == NULL)) { 225 puts("Not exist ')'"); 226 exit(0); 227 } else { 228 // Exist brackets 229 start = (int)(bra - samplename); 230 end = (int)(ket - samplename); 231 if ((end - start) == 1) { 232 puts("Error"); 233 puts("Nothing is entered in parenthese."); 234 exit(0); 235 } 236 return; 237 } 238} 239 240 241Molecule_t *parse(void) { 242 int i, j, k; 243 char v[64] = {}, samplename[64] = {}; 244 245 puts("Enter sample name."); 246 printf("Chemical formula: "); 247 scanf("%s", samplename); 248 249 JudgeBrackets(samplename); 250 251 stack_push(newMolecule()); 252 for (i=0; i<strlen(samplename); i++) { 253 memset(v, 0, sizeof(v)); 254 v[0] = samplename[i]; 255 if (isDigit(v[0])) { 256 for (j=i+1, k=1; j<strlen(samplename) && isDigitOrPeriod(samplename[j]); k++, j++, i++) { 257 v[k] = samplename[j]; 258 } 259 setRatio(stack_peek(), atof(v)); 260 } else if (strcmp(v, "(") == 0) { 261 stack_push(newMolecule()); 262 } else if (strcmp(v, ")") == 0) { 263 Material_t *material = (Material_t *)stack_pop(); 264 add(stack_peek(), material); 265 } else { 266 267 if ((samplename[i+1]>='a') && (samplename[i+1]<='z')) { 268 v[1] = samplename[i+1]; 269 i++; 270 } 271 272 add(stack_peek(), (Material_t *)search_atom(v)); 273 } 274 } 275 return stack_pop(); 276} 277 278int main(int argc, char *argv[]) { 279 280 double MW; //Molecular Weight 281 282 MW = getWeight(parse()); 283 printf("%lf g/mol\n", MW); 284 285 return 0; 286} 287

投稿2019/03/01 10:40

RaitoN

総合スコア72

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問