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

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

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

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

Q&A

解決済

3回答

920閲覧

Google mapのURLから緯度、経度、ズーム値を抽出し出力したい

rft3

総合スコア7

C

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

0グッド

0クリップ

投稿2020/06/29 14:33

Google mapのURL https://www.google.com/maps/@35.6896342,139.6921007,15z から
緯度 double latitude、経度 double longitude、ズーム値 int zoom
を抽出して、各変数に代入して出力したいです。しかし条件として、

条件1:URLはコマンドライン引数から指定する
条件2:url.hのURL構造体は使用しない
条件3:strchr以外の文字列操作関数を使用しない

という条件が課せられています。とりあえず抽出するところまでは自分で書いてみたのですが、正直自信はないうえにmain関数内をどう書けばいいのかがわかりません。
どうかご教授いただけないでしょうか。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4 5typedef struct{ 6char *service; 7char *host; 8double latitude; 9 double longitude; 10 int zoom; 11 12} URL; 13 14void parse_url(const char *url_str, URL *url){ 15 char *p = NULL; 16 char *host_path = calloc(strlen(url_str)+1, sizeof(char)); 17 18 p = strchr(host_path, '@'); 19 if(p == NULL) url->latitude = NULL; 20 else{ 21 url->latitude = calloc(strlen(p)+1, sizeof(char)); 22 url->latitude = atoi(p+1); 23 *p = '\0'; 24 } 25 p = strchr(host_path, ','); 26 if(p == NULL) url-> longitude = NULL; 27 else{ 28 url->longitude = calloc(strlen(p)+1, sizeof(char)); 29 url->longitude = atoi(p+1); 30 *p = '\0'; 31 } 32 p = strchr(host_path, ','); 33 if(p == NULL) url-> zoom = NULL; 34 else{ 35 url->zoom = calloc(strlen(p)+1, sizeof(char)); 36 url->zoom = atoi(p+1); 37 *p = '\0'; 38 } 39 40} 41 42 43int main(int argc, char *argv[]){ 44 45 46 47printf("緯度:%d 経度:%d ズーム値:%d\n", latitude, longitude, zoom); 48} 49 50

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

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

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

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

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

kazuma-s

2020/06/29 15:13

コンパイルしたらエラーメッセージが表示されるでしょう。 どの部分が分かりませんか?
rft3

2020/06/29 15:48

incompatible types when assigning to type ‘double’ from type ‘void *’ というエラーメッセージが多く表示されるのですが解決方法がわかりません。
guest

回答3

0

ベストアンサー

C

1#include <stdio.h> // sscanf 2#include <stdlib.h> // strtod 3#include <string.h> // strchr 4 5typedef struct { 6 char *service; 7 char *host; 8 double latitude; 9 double longitude; 10 int zoom; 11} URL; 12 13void parse_url(const char *url_str, URL *url) 14{ 15 url->service = url->host = NULL; 16 url->latitude = url->longitude = url->zoom = 0; 17 char *p = strchr(url_str, '@'); 18 if (p == NULL) return; 19 char *q; 20 url->latitude = strtod(++p, &q); 21 if (q == p) return; 22 url->longitude = strtod(++q, &p); 23 if (p == q) return; 24 url->zoom = strtol(++p, &q, 10); 25} 26 27int main(int argc, char *argv[]) 28{ 29 if (argc != 2) return 1; 30 // argv[1] = "https://www.google.com/maps/@35.6896342,139.6921007,15z"; 31 URL url; 32 parse_url(argv[1], &url); 33 printf("緯度:%.7f 経度:%.7f ズーム値:%d\n", 34 url.latitude, url.longitude, url.zoom); 35} 36

別解(service と host の読み取りも追加してみました)

C

1#include <stdio.h> // sscanf 2#include <string.h> // strdup 3 4typedef struct { 5 char *service; 6 char *host; 7 double latitude; 8 double longitude; 9 int zoom; 10} URL; 11 12void parse_url(const char *url_str, URL *url) 13{ 14 char service[32]; 15 char host[128]; 16 if (sscanf(url_str, "%31[^:]://%127[^/]/%*[^@]@%lf,%lf,%d", service, 17 host, &url->latitude, &url->longitude, &url->zoom) == 5) { 18 url->service = strdup(service); 19 url->host = strdup(host); 20 } 21 else { 22 url->service = url->host = NULL; 23 url->latitude = url->longitude = url->zoom = 0; 24 } 25} 26 27int main(int argc, char *argv[]) 28{ 29 if (argc != 2) return 1; 30 // argv[1] = "https://www.google.com/maps/@35.6896342,139.6921007,15z"; 31 URL url; 32 parse_url(argv[1], &url); 33 printf("緯度:%.7f 経度:%.7f ズーム値:%d\n", 34 url.latitude, url.longitude, url.zoom); 35}

コメントをお願いします。

投稿2020/06/29 16:21

kazuma-s

総合スコア8224

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

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

rft3

2020/06/29 16:37

ありがとうございます。strtod、という関数を初めて知りましたがdouble型の表現に使用するものなのですね。 strchr以外のの文字列操作関数を使用しない、という条件に囚われて思考停止していたようです。参考にさせていただきます。
guest

0

いくつか問題点があります。

1. strchr呼び出し後のエラー処理

c

1if(p == NULL) url->longitude = NULL;

のようなコードをいくつか見ますが、NULLはポインタ型に対してのみ使われるべきです。また、エラーが起きたときには、処理を続けるのではなく直ちに関数を抜けて呼び出し元にエラーを通知するべきです。

今回はさほど複雑なエラーハンドリングは必要ないでしょうから、単にbool型を使いましょう。stdbool.hのincludeが必要です。

すると

c

1if(p == NULL) return false;

のようになります。

2. 謎のメモリー確保

c

1char *host_path = calloc(strlen(url_str)+1, sizeof(char)); 2 3url->latitude = calloc(strlen(p)+1, sizeof(char));

何をしたかったのかさっぱりわかりません。削除します。

3. エラー時にurlを書き換えてしまう

処理中にエラーが有ったとき、呼び出し元を書き換えてしまうのはあまりいい設計とは言えません。そこで

c

1bool parse_url(const char *url_str, URL *dest_url){ 2 URL url; 3 //do something 4 *dest_url = url; 5 return true; 6}

のようにします。これなら書き換わりません。構造体は=代入でコピーできます。

4. atoiを使わない

  • atoiは文字列を正しく変換できたか知ることができない
  • 変換が終わった直後の文字列の位置を知ることができない

という問題があります。あとそもそもatoiは整数への変換なのでdouble型への変換には使えないですね。

代わりにstrtod/strtolを使います。使い方の解説は
C言語で安全に標準入力から数値を取得
を見てください。

strtod/strtolに渡す第2引数のendptrには変換が終わった直後の文字へのポインタが返されます。つまりなんどもstrchrを呼ぶ必要がありません。

結果

c

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <errno.h> 5#include <stdbool.h> 6enum { 7 // 21が最大だと思われる 8 ZOOM_MAX = 21, 9}; 10typedef struct{ 11 char *service; 12 char *host; 13 double latitude; 14 double longitude; 15 int zoom; 16} URL; 17 18bool parse_url(const char *url_str, URL *dest_url){ 19 char *p = strchr(url_str, '@'); 20 if(p == NULL) return false; 21 ++p; 22 URL url; 23 // strtodで正しく変換できたか知るためとその後の処理に必要 24 char* endptr = p; 25 // strtodの呼び出し前にはerrnoをリセットする 26 errno = 0; 27 url.latitude = strtod(p, &endptr); 28 if (0 != errno || (0 == url.latitude && endptr == p)) return false; 29 // endptrは数値の直後の文字へのポインタとなっている 30 if (endptr[0] != ',') return false; 31 p = endptr + 1; 32 errno = 0; 33 url.longitude = strtod(p, &endptr); 34 if (0 != errno || (0 == url.longitude && endptr == p)) return false; 35 // endptrは数値の直後の文字へのポインタとなっている 36 if (endptr[0] != ',') return false; 37 p = endptr + 1; 38 errno = 0; 39 long z = strtol(p, &endptr, 10); 40 if (0 != errno || (0 == z && endptr == p) || z < 0 || ZOOM_MAX < z) return false; 41 url.zoom = (int)z; 42 if (endptr[0] != 'z') return false; 43 *dest_url = url; 44 return true; 45} 46 47 48int main(int argc, char *argv[]){ 49 if (argc != 2) return 1; 50 URL url; 51 if (!parse_url(argv[1], &url)) return 2; 52 printf("緯度:%f 経度:%f ズーム値:%d\n", url.latitude, url.longitude, url.zoom); 53 return 0; 54}

こんな感じでどうでしょ。

https://wandbox.org/permlink/dd8yA6Gb4aHNILDg

投稿2020/06/29 16:18

yumetodo

総合スコア5850

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

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

rft3

2020/06/29 16:31

strtod/strtolというものは初めて聴きました。参考にさせていただきます。
guest

0

ええと、atoiとか使ってるから、その手の数値生成関数は文字列操作関数とはみなさないってことだよね。
どうも、提示されているソースには、「latitudeなどを文字列で保持しようとした痕跡(callocとか)」が残っているんだけど。

C

1#include <stdio.h> 2#include <stdlib.h> 3#include <string.h> 4#include <math.h> 5 6typedef struct { 7 char *service; 8 char *host; 9 double latitude; 10 double longitude; 11 int zoom; 12} URL; 13 14void parse_url(const char *url_str, URL *url) { 15 char *p; 16 17 url->latitude = url->longitude = NAN; 18 url->zoom = 0; 19 20 21 p = strchr(url_str, '@'); 22 if (p == NULL) { 23 return; 24 } 25 url->latitude = strtod(p + 1, NULL); 26 27 p = strchr(p + 1, ','); 28 if (p == NULL) { 29 return; 30 } 31 url->longitude = strtod(p + 1, NULL); 32 33 p = strchr(p + 1, ','); 34 if (p == NULL) { 35 return; 36 } 37 url->zoom = strtol(p + 1, NULL, 10); 38} 39 40int main(int argc, char *argv[]) { 41 URL url; 42 if (argc <= 1) { 43 puts("引数にGoogle MAPのURLを指定"); 44 return 1; 45 } 46 parse_url(argv[1], &url); 47 printf("緯度:%.7lf 経度:%.7lf ズーム値:%d\n", url.latitude, url.longitude, 48 url.zoom); 49 50 return 0; 51}

投稿2020/06/29 15:47

Daregada

総合スコア11990

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

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

rft3

2020/06/29 16:29

すみません、参考にしたコードをコピーした部分を書き換え忘れていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問