文字列配列のほしい部分だけを抜き出して数値にする方法(PIC)

このQ&Aのポイント
  • 現在PICマイコンでPCからGPSの座標データを取得し、そのデータ列から必要な部分だけ抜き出す処理を行う方法について説明します。
  • GPSデータのN以降の数値とE以降の数値を文字列から数値に変換する方法について説明します。
  • アドバイスとして、正しい数値への変換が行われない可能性があるため、データの取得と変換処理の順序や条件文の確認をおすすめします。
回答を見る
  • ベストアンサー

文字列配列のほしい部分だけを抜き出して数値にする方法(PIC)

現在PICマイコンでPCからGPSの座標データを取得し,そのデータ列から必要な部分だけ抜き出す処理をくんでいるんですがうまくいきません。 pcとマイコンの接続はrs23-2c コンパイラはccsc pic:16f877 GPSデータ↓ @051125012151N3529558E13638533G009+00021E0000N0000D0003 このデータのN以降の「3529558」とE以降の「13638533」の文字列を数値にしたい。 delay_ms(300); output_b(0b00000001);//デバック用LED点灯 delay_ms(300); gets(mes);    //ここでGPSデータをmesに代入する output_b(0b00000011); len_N=0; for(i=0;i<58;i++){  if(mes[i]=='N'){   len_N=i;   break;  } } printf("\r\n"); n=atoi(mes[len_N+1]); //ここで試しに一文字分だけ数値にする処理を行ったが処理が停止する。 printf("n:%ld",n); アドバイスお願いします

質問者が選んだベストアンサー

  • ベストアンサー
  • techa
  • ベストアンサー率60% (41/68)
回答No.4

以下のようにすると切り出しぐらいはできるようです。 ただRAM384バイトしかないので変数領域に気をつけてください。 一応コンパイルは通るようです。実際の挙動がそのようになるかは確認していません。 また、よく考えるとatoi()ではだめですよね。 CCS-Cのlong型は16ビットですからunsigned指定をしても65535までしかカウントできません。 サンプルにある13638533なんて演算できませんもんね。 ここを数値化する方法は別に考えないといけませんね。 #include <TEST.H> char mes[60] = "@051125012151N3529558E13638533G009+00021E0000N0000D0003"; void main() { int numN=0 ; int Nflag=0; int numE=0; int Eflag = 0; int i; char mesN[10] = {0,0,0,0,0,0,0,0,0,0}; char mesE[10] = {0,0,0,0,0,0,0,0,0,0}; setup_counters(RTCC_INTERNAL,RTCC_DIV_2); setup_port_a(NO_ANALOGS); setup_adc(ADC_CLOCK_INTERNAL); while(1){ printf("Input> ");printf(mes); printf("\r\n"); for(i=0;i<58;i++){ if ( mes[i]=='N' ){ Nflag = 1; Eflag = 0; } if ( mes[i]=='E' ){ Nflag = 0; Eflag = 1; } if ( mes[i]=='G' ){ Nflag = 0; Eflag = 0; } if ( Nflag ) { mesN[numN] = mes[i]; numN++; } if ( Eflag ) { mesE[numE] = mes[i]; numE++; } } printf( mesN ); printf("\r\n"); printf( mesE ); printf("\r\n"); } }

kiyumoto
質問者

お礼

ありがとうございます、参考にします

その他の回答 (5)

  • rentahero
  • ベストアンサー率53% (182/342)
回答No.6

>ポインタ操作ができないようです ということであれば、 文字列の処理をどうするのか補足してください。 文字列を数字にするのは変数演算でできると思うのですが、できませんか?

kiyumoto
質問者

補足

回答者の方々のおっしゃるとおり、 longでもビット数が足りないことが分かりました。 いままで授業ではPC上のソフトしか組んだことがないので まったくの無知でした。 どっちみち、うまく取り出したとしても変数に 格納できないし、unsignedではなんか反則技みたいで 最終的には dig(int) min(int) sec(float) と三つに分けるつもりなので ばらばらで処理していきたいと思います ちなみに 16F877に書き込んだところ すでにRAMがいっぱいです。 cssのマニュアルには なるべくローカル変数をへらせ としかかいてありません 数回しか行かない関数はメイン文に入れろ と先生はいうので そのとおりにしてもぜんぜん足らないので PICを変えるべきなのか迷っています。

  • rentahero
  • ベストアンサー率53% (182/342)
回答No.5

そういえばこれGPSですよね。ということはわたってくる数値は固定小数点だったはず。 であれば、 float n, e, pow; n = 0; pow = 10; for(i = 1; mes[len_N + i] >= '0' && mes[len_N + i] <= '9'; i++) {  n += (mes[len_N + i] - '0') * pow;  pow /= 10; } e = 0; pow=100; for(i = 1; mes[len_E + i] >= '0' && mes[len_E + i] <= '9'; i++) {  e += (mes[len_E + i] - '0') * pow;  pow /= 10; } ということではないかと思います。

kiyumoto
質問者

お礼

参考にさせていただきます。

  • rentahero
  • ベストアンサー率53% (182/342)
回答No.3

rentaheroです。 PICは触ってないので、一般人で。 そもそもatoi(3)に対する引数の型が間違ってます。 atoiは文字列へのポインタを渡さなければなりません。 mesはchar のポインタか配列のようですから、 mes[len_N+1]はcharそのものです。 1文字だけ数値にしたい場合は、 n = mes[len_N+1]-'0'; とするべきだし、 同じ位置からintとして数値を取り出したい場合は、 n = atoi(&mes[len_N + 1]); または n = atoi(mes + len_N + 1); となります。 'N'を検出する処理は問題ないと思います。

kiyumoto
質問者

補足

ポインタ操作ができないようです

  • mac_res
  • ベストアンサー率36% (568/1571)
回答No.2

PCでやってもatoi(3)はエラーになりますね。 #include <stdio.h> #include <stdlib.h> #define NGPSBUFF 58 int main(void) { char mes[NGPSBUFF]; int i; long N, E; char *n, *e; gets(mes); //ここでGPSデータをmesに代入する for (i = 0; i < NGPSBUFF; i++) { if (mes[i] == 'N') break; } ++i; n = &mes[i]; for (; i < NGPSBUFF; i++) { if (mes[i] == 'E') break; } mes[i] = '\0'; ++i; e = &mes[i]; for (; i < NGPSBUFF; i++) { if (mes[i] == 'G') break; } mes[i] = '\0'; N = atoi(n); printf("n:%ld\n", N); E = atoi(e); printf("e:%ld\n", E); return 0; }

kiyumoto
質問者

補足

一部参考にしてみましたがやはりポインタ操作とのころで 処理が停止しています。 その問題を回避しつつ、数字の文字列をだすには どうしたらいいでしょうか?

  • techa
  • ベストアンサー率60% (41/68)
回答No.1

atoi関数の考え方がまずいですよね。 atoiに与える引数はキャラクタ型ポインタですからnullポインタが出てくるところまで動作してしまうんではないでしょうか。 char buf[2] = {0,0}; とでもしておいて、 buf[0] = mes[len_N+1]; n=atoi(buf); printf("n:%d",n); とでもすればうまくいきそうにみえますね。

kiyumoto
質問者

補足

知人いわく このコンパイラはポインタ操作ができないらしいのです どうしたらいいでしょうか? また文字列を取り出す時にはどうしたらいいでしょうか?

関連するQ&A

  • 文字列

    下のプログラムは何をするためのプログラムなのか教えてください。 個人的にはJISコードに関係していると思うのですがさっぱりわかりません。 どなたか詳しい説明お願いします。 #include <stdio.h> #define LEN 255 int main(void) { char str[LEN]; char cipher[LEN]; int ikey; int i,n; printf("文字列を入力せよ : "); scanf("%s", str); printf("鍵を入力 : "); scanf("%d", &ikey); i = 0; while (str[i]!='\0') { n = (str[i]-'A'+ikey)%26; cipher[i] = 'A'+n; ++i; } cipher[i] = '\0'; printf("%s\n", cipher); return 0; }

  • 文字列の動的確保とポインタ配列について

    C言語についての質問です。 現在、キーボードから文字列を読み込みファイルに保存するプログラムを作成しています。 プログラムの条件は、以下の通りです。 1: キーボードから英数字(最長でMAX_LEN(1000)-1文字)を入力して文字列(文字配列)dataに格納後、画面に表示する。 2: 入力された文字列と同じ長さの文字列を格納する領域を動的に確保し、文字列dataをその領域に コピーする。なお、必要な文字配列の長さは文字列の長さ+1バイトである。 3: 文字列endが入力されるか、入力された文字列がNUM_STRING(10)個になるまで1~2の処理を繰り返す 4: 各文字列へのポインタを格納する(char *)型ポインタの配列str_p(サイズ:NUM_STRING)を定義して利用する。 5:1~2の処理が終了した後で、メモリに格納されたすべての文字列をファイルに出力する。ファイル名はoutput.txtとし、最初の行に文字列の個数を、次の行以降に入力された順番と「逆の順番」で文字 列を出力すること。 実行例 input ->st22 st22 input->st1 st1 end ファイルの中身 2 st1 st22 現在完成しているプログラムは以下の通りです。 #include<stdio.h> #include<string.h> #include <stdilb.h> #define NUM_STRING 10 #define MAX_LEN 1000 int main (void) { int n, i; char data[MAX_LEN] = {}; char *str_p[NUM_STRING]; FILE *fp; do { printf("input->"); scanf("%s", data); if (strcmp(data, "end") == 0) { break; } else { printf("%s\n", data); n++ 2の処理 } while(n <= NUM_STRING); if ((fp = fopen("output.txt", "w")) == NULL) { fprintf(stdout, "File open error\n"); } fprintf(fp, "%d\n", n); for (i = n-1; i>0; i--) fprintf(fp, "5s\n", str_p[i]); fclose (fp); return 0; } 特に動的確保のところがよく分かりません。 回答よろしくお願いします。       

  • c言語 文字列と配列

    #include<stdio.h> int charlen(int n); void cap2sml(int b); int main() { char a[100],b[100]; int n,i; /*Input CARACTERS*/ printf("CAPITAL?\n"); fgets(a,100,stdin); charlen(n); printf("total cahrs=%d\n",n); //printf in main cap2sml(i); printf("small=%s\n",b); return(0); int charlen(int n) n=0; while(1){ if(a[n]=='\0') break; n++; } void cap2sml(int b) int i; for(i=0;a[i]!='\0';i++){ b[i]=a[i]+0x20; } b[i]='\0' } のプログラムでエラーがでるのですが、どこを直せばよいでしょうか? ユーザー関数を使い文字列(大文字)を入力したときの文字列の長さと大文字を小文字に変化するプログラムです

  • geko201とマイコンのシリアル通信について

    GPS受信機(geko201)をマイコン(pic18f452)の基板にrs23-2cで接続して、 GPS受信機からのデータを取り、その数値を計算するプログラムをC言語で組んでいます。 処理手順としては マイコン側のボタンを押すと、 GPS受信機からのデータ(@051125004805N3529538E13638632G005+00041E0000N0000D0000) を受信してその値の計算をはじめます。 そこで問題があり、 仮想GPSとしてプログラムで任意のタイミングで一件だけマイコンにGPSデータを送った場合 ちゃんと計算してくれるんですが、 本物のGPS受信機は1秒毎にデータを垂れ流し状態で そこで受信したら、受信待ちで止まってしまいます 改善策がわからないので、どなたか教えてください 受信部分のソース↓ while(1) { if(input(PIN_A0)){ gets(mes);          以下略 } }//roop end

  • 文字列を表すための配列とポインタ

    文字列を表すための配列とポインタ  配列とポインタは同様に扱えるもの、と思って、次のプログラムを作りました。処理系は、Visual Studio 2010 コマンドプロンプトです。 #include <stdio.h> void main(void) { char a[256]; char *b; printf("文字列を入力してください。\n"); printf("例「abcde」\n\n"); printf("配列型文字列を使います。\n"); scanf("%s", a); printf("文字列は%sです。\n\n", a); printf("ポインタ型文字列を使います。\n"); scanf("%s", b); printf("文字列は%sです。\n", b); }  すると、まずコンパイル時に、 「warning C4700: 初期化されていないローカル変数'b'が使用されます」 と表示されました。そして、実行すると、「配列型文字列」の方は問題ないのですが、「ポインタ型文字列」の方の実行後に、 「x.exeは動作を停止しました。 問題が発生したため、プログラムが正しく動作しなくなりま した。プログラムは閉じられ、解決策がある場合は Windowsから通知されます。」 と表示され、エラーとして終了してしまいます。 「char *b;」 と宣言するところが問題のようですが、なぜなのかが分かりません。どなたか、解説をお願いします。

  • C言語 配列 文字列

    配列と文字列をあわせて使う以下のようなプログラムを作りました.エラーはでないのですが,最後のprintfの部分が表示されません.どこが間違っているのでしょうか? /*文字列を入力し,入力した文字列を逆の順番で表示するプログラム*/ #include<stdio.h> #include<string.h> int main(void) { int i,n,t; char mozi[100]; printf("100字以下の文章を入力したら,逆にして表示します.\n"); gets(mozi); n=strlen(mozi); if(n%2) { for(i=0;i<(n-1)/2;i++) { t=mozi[i]; mozi[i]=mozi[n-i]; mozi[n-i]=t; } } else { for(i=0;i<n/2;i++) { t=mozi[i]; mozi[i]=mozi[n-i]; mozi[n-i]=t; } } printf(mozi); return 0; }

  • bashで配列の個数部分を変数で指定するとエラーに

    bashで配列の個数部分を変数で指定するとエラーになってしまいます。 #!/bin/bash aa[0]="a0" aa[1]="a1" aa[2]="a2" bb[0]="b0" bb[1]="b1" bb[2]="b2" bb[3]="b3" cc[0]="c0" cc[1]="c1" cc[2]="c2" cc[3]="c3" cc[4]="c4" list=(aa bb cc) for i in ${list[@]} do eval echo "$i=\${#$i[*]}" n="\${#$i[*]}" mes="\${$i[$(( ${RANDOM} * 3 / 32768 ))]}" eval echo "$mes \${$i[$(( ${RANDOM} * 3 / 32768 ))]}" done $ . list-test.sh aa=3 a1 a2 bb=4 b2 b2 cc=5 c0 c2 上記の下記箇所の「各配列の個数部分の3」をイメージ的には変数で指定したいです。 mes="\${$i[$(( ${RANDOM} * 3 / 32768 ))]}" ↓ mes="\${$i[$(( ${RANDOM} * $n / 32768 ))]}" $nのように指定すると、下記のエラーになってしまいます。 >bash: 29205 * ${#aa[*]} / 32768 : 構文エラー: オペランドが予期されます (エラーのあるトークンは "${#aa[*]} / 32768 ") ${n}や\$nや($n)など色々試してみたのですが、解決できませんでした。 恥ずかしながら、どなた様かご教授ねがえませんでしょうか

  • 文字列の入力、数値変換について

    入力された数字を数値に変換するプログラムを作ったのですが、うまくいきません。 #include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include <ctype.h> unsigned long long atollu(char[16]); void main(void){ unsigned long long input; char str[16]; char test[16] = "123456789012345"; int i,j=1; //atollu の動作確認・・・(1) printf("atollu test:%llu\n\n",atollu(test) ); //入力 NG: printf("%d回目 数値を入力(1~100000000000000 終了:exit)>",j); gets(str); input = atollu(str); //str と atollu(str) の確認 printf("%s %llu\n\n",str,atollu(str)); //exitと入力すると終了・・・(2) if(strcmp(str, "exit") == 0){ exit(0); } //数字以外がないか確認・・・(3) else { for( i=0; i<=15; i++){ if(isdigit(str[i]) == 0){ printf("NG\n"); for( i=0; i<=16; i++){ str[i]='\0'; } printf("moji\n"); j++; goto NG; } } } //範囲外 if(input>100000000000000 || input==0){ printf("NG\n"); printf("hani\n"); j++; goto NG; } printf("\n入力値は% llu",input ); } unsigned long long atollu(char str[16]){ unsigned long long t=0; int i,n; n = strlen(str) - 1; for( i=0; i<=15; i++){ if(str[i] == '\0'){ str[i] = 0;} else { t = t + (str[i] - '0') * pow(10.0,n-i);} } str[16] = '\0'; return t; } /* 数字を数値に変換する関数atolluは自分で作りました。 これの動作は(1)でちゃんとした値が出ているのでうまくできているようです。 (2)も"exit"と入力すれば終了するのでうまくいっています。 また、例えば "12" と入力したとき 12 9 NG moji 表示されますが、二回目以降は 12 12 NG moji となり、atollu(str)はうまく出力されている一方で、最後に「moji」と出てきているので、(3)でうまくいっていないようです。 どう直すべきなのか見当もつかないので困っています。 よろしくお願いします。

  • C言語で2桁Hex文字列を10進数値に変換する方法

    C初心者です。よろしくお願いします。 測定器からシリアルで送られてくる2桁のHexデータ(リトルエンディアン)を10進数値に変換したいのですが、ネットでいろいろ調べてもよく解りません。 ネット上にあったプログラムを参考にして、次のようにやっています。 char d[3]; //受信データ // データ受信処理後 int i=0, c=0, n; while(d[i] != '\0'){ n = n * 0x10; c = d[i++]; if((c >= '0') && (c <= '9')){ n += c - '0'; } else if((c >= 'A') && (c <= 'F')){ n += c - 'A' + 10; } } printf("%d\n",n); 結果を表示すると’0’になってしまいます。 どこがダメなのか、よろしくお願いします。

  • 文字列から文字を探す

    以下のプログラムです。 #include <stdio.h> main () { char s[]="I love cat and dog."; char c='a'; char *p=s; int n=0; printf("\"%s\"の中から\'%c\'を探します。",s,c); while(*p != '\0') { if(*p == 0) { printf("%d文字目で発見しました。\n",p-s+1); n++; } p++; } if(n == 0) printf("1つも見つかりませんでした。\n"); else printf("全部で%d個見つかりました。\n",n); } C言語の本で勉強しています。 ・p-s+1の意味がわかりません。 ここには何が割り当てられているのでしょうか? ・*pとpの違いもあいまいです。 ・\"%s\"は「"」を印刷するためには必要なのでしょうか? どう質問していいのかもわからないのですが、よろしくお願いします。

専門家に質問してみよう