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

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

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

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

Q&A

解決済

6回答

9807閲覧

C言語 : 文字列を数値に変換して足し算

ryota1017stars

総合スコア21

C

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

0グッド

2クリップ

投稿2018/09/03 07:56

実現したいこと

30 5

この文字列を
足し算して35と出力したい

エラー

30+5と出力されてしまう

該当のソースコード

c

1int main(void){ 2 char str[] = "30 5"; 3 4 str[2] = '+'; 5 int tashizan = atoi(str); 6 7 return 0; 8}

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

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

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

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

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

guest

回答6

0

なんかstrtokとかatoiとかいう声が聞こえていますが、どれも使い勝手が今ひとつだったりエラー捕捉に難があるので、strtol系関数を使いましょう。


strtol系関数は、概ね

c

1long int strtol(const char *nptr, char **endptr, int base);

のような宣言になっているわけですが、nptrに渡された文字列の先頭から、数値に変換可能な位置までを数値に変換します。そしてendptrがNULLポインタではないならば、*endptrに変換可能でなくなった位置へのポインタを書き込みます。

例えば

c

1"3+4";

という文字列があったとき、これをstrtol系関数にわたすとendptrには+の部分を指すポインタが書き込まれます。

これを利用すると

c

1#include <stdio.h> 2#include <math.h> 3#include <stdlib.h> 4#include <errno.h> 5#include <ctype.h> 6 7void parse(const char* str){ 8 char* endptr1 = NULL; 9 errno = 0; 10 const int l = (int)strtol(str, &endptr1, 10); 11 if(errno != 0 || (0 == l && endptr1 == str)) exit(1); 12 const char* op = endptr1; 13 for(;isspace(*op); ++op); 14 const char* r_str = op + 1; 15 for(;isspace(*r_str); ++r_str); 16 char* endptr2 = NULL; 17 const int r = (int)strtol(r_str, &endptr2, 10); 18 if(errno != 0 || (0 == l && endptr2 == str)) exit(1); 19 printf( 20 "input: %s\n" 21 "left: %d\n" 22 "op: %c\n" 23 "right: %d\n", 24 str, l, *op, r 25 ); 26} 27int main(void) 28{ 29 parse("3+4"); 30 parse("3-4"); 31 parse("3 + 4"); 32 return 0; 33}

https://wandbox.org/permlink/RrMVCnLKt4oT7GKo

のようにパースすることが可能です。

C言語で安全に標準入力から数値を取得

も参考に


追記

なんか他の方がもうほぼそのまま答えのを貼ってしまっている状況で自重しても仕方ないので貼っておきます。ASTをunionとかでもうちょっとうまくやれば演算子の優先順位とかとかも作れます。

https://wandbox.org/permlink/p1BzBKX3YSdDUgBq

投稿2018/09/03 14:11

編集2018/09/08 11:56
yumetodo

総合スコア5850

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

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

退会済みユーザー

退会済みユーザー

2018/09/03 17:57 編集

strtolとはどのような働きをするのでしょうか? ググってもいまいち理解できません、今回の質問の解決に役に立つ回答なのでしょうか?
yumetodo

2018/09/04 01:54

一応多分やりたかったであろう四則演算をできるやつも作ったことには作ったので、BAが選ばれたらここに貼りますね~。
退会済みユーザー

退会済みユーザー

2018/09/04 13:28 編集

上の文は、やりたいことは何んとなくわかってきたけど、難しいです( ノД`) strtolの第二引数はなぜダブルポインタなのでしょうか?
yumetodo

2018/09/04 13:40

Cで文字列といえばchar*型ですよね?呼び出し側のchar*型変数に書き込みたいんだから、そのポインタを関数の引数に渡せばいいわけで、つまりchar**型となりますね?
guest

0

・"30"を取り出し、これを整数に変換。
・次に"5"を取り出し、これを整数に変換
・その整数どおしを加算する

投稿2018/09/03 08:00

y_waiwai

総合スコア87774

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

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

0

ベストアンサー

2個だけでなく、10 個以下の数字までを足し算できるようにしてみました。
calc.c

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <limits.h> 4 5int str_to_nums(char* str, int* nums) { 6 char* start_p = str; 7 char* end_p = str; 8 int count = 0; 9 10 while (*end_p) { 11 long n = strtol(start_p, &end_p, 10); 12 if (start_p == end_p) { 13 puts("数値に変換できませんでした"); 14 return -1; 15 } 16 if (n > INT_MAX || n < INT_MIN) { 17 puts("int型には変換できません"); 18 return -1; 19 } 20 nums[count++] = n; 21 start_p = end_p; 22 // printf("count %d, n %d\n", count, nums[count - 1]); 23 } 24 return count; 25} 26 27 28int main(void) { 29 char* strs[] = { 30 " 30 5", 31 " 1 2 3 4" 32 }; 33 34 int nums[10]; 35 str_to_nums(strs[0], nums); 36 printf("'%s' -> %d\n", strs[0], nums[0] + nums[1]); 37 38 int count = str_to_nums(strs[1], nums); 39 int sum = 0; 40 for (int i = 0; i < count; i++) { 41 sum += nums[i]; 42 } 43 printf("'%s' -> %d\n", strs[1], sum); 44 45 return 0; 46}

実行例
イメージ説明

投稿2018/09/08 10:26

katoy

総合スコア22324

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

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

0

既に関数を用いる方法は他の方々が回答されているので、私からは地道な手法の提案を。

1.一般的に使用される計算式(中置記法)を逆ポーランド記法に変換
2.ポーランド記法を元に演算

というのはいかがでしょう。

2.の演算部分はこんな感じになるかと。

C

1// 逆ポーランド記法の計算 2int calc_rpn(char *s) 3{ 4 int a, b, n; 5 6 while (*s) { 7 8 // 数値の場合はスタックに積む 9 if (・・・) { 10 // TODO 取り出してスタックに積む 11 12 // オペランドの場合は計算する 13 } else { 14 switch (*s) { 15 case '+': 16 a = pop(); 17 b = pop(); 18 push(b+a); 19 break; 20 case '-': 21 a = pop(); 22 b = pop(); 23 push(b-a); 24 break; 25 case '*': 26 a = pop(); 27 b = pop(); 28 push(b*a); 29 break; 30 case '/': 31 a = pop(); 32 b = pop(); 33 if (a == 0) break; 34 push(b/a); 35 break; 36 case '%': 37 a = pop(); 38 b = pop(); 39 if (a == 0) break; 40 push(b%a); 41 } 42 s++; 43 } 44 } 45 return pop(); 46}

投稿2018/09/04 14:02

Simb

総合スコア118

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

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

0

sscanf()関数を用いる方法もあります。

C

1#include <stdio.h> 2 3int main(void){ 4 char str[] = "30 5"; 5 int n; 6 int m; 7 8 if (sscanf(str, "%d %d", &n, &m) != 2){ 9 return 1; 10 } 11 12 printf("%d + %d = %d\n", n, m, n + m); 13 14 return 0; 15} 16

投稿2018/09/04 10:32

shsh_

総合スコア113

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

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

退会済みユーザー

退会済みユーザー

2018/09/04 13:24

優しくて良いですね
ryota1017stars

2018/09/06 05:54

ご回答ありがとうございます。 if (sscanf(str, "%d %d", &n, &m) != 2){ return 1; } とありますが、なぜreturnが"1"なのでしょうか?
cateye

2018/09/08 09:22 編集

コマンドの実行結果を判断するために使います。 Unix系のOSでは、echo $? で表示できます。 #include<stdio.h> int main(int agc, char *agv[]) { if(agc != 2){ return 1; } return 0; } usr~/test/c % ./a.out usr~/test/c % echo $? 1 usr~/test/c % ./a.out 2 usr~/test/c % echo $? 0
guest

0

当たり前です。

文字列は数列とは違いますよ。

計算するなら、トークン分割で分割して、それをint型かなんかに変換してから計算。

C言語では トークン分解は strtok関数, 文字列からint型変換は atoi関数を使う。

投稿2018/09/03 08:03

BeatStar

総合スコア4958

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問