GPS受信の抜き出しについて

このQ&Aのポイント
  • 大学卒業間近の大学4年生が、卒業研究の一環としてシリアル通信でGPSの構文をテキストファイルに書き込むプログラムを作成しています。
  • しかし、中途半端なプログラムの勉強のために、生データから重要な部分を抜き出す方法がわかりません。
  • 北緯と東経の数値のみを抜き出して書き込むプログラムを作成したいのですが、どの部分にどのような文を入力すれば良いか分かりません。
回答を見る
  • ベストアンサー

GPS受信の抜き出しについて

大学卒業間近の大学4年生です。 現在、卒業研究の一環でシリアル通信でGPSの構文をテキストファイルに書き込むプログラムを作成しています。 生データをテキストファイルに書き込むまではできたのですが… なにぶん中途半端にプログラムの勉強をしていたのでそこから大事な部分を抜き出す作業がわからなくて困っています。(サイトにあるサンプルプログラムを参考にしてもエラーばかりが出てしまいます。) 北緯と東経の数値のみを抜き出して書き込むプログラムを作成したいのですがどの部分にどういう文を打ち込めばいいのでしょうか? お分かりの方、どうか教えて貰えませんでしょうか? ちなみに環境はC++で使っているソフトはMicrosoft Visual Studioです。 現在出来ているプログラムは以下のとおりです。 #include <stdio.h> #include <stdlib.h> #include <Windows.h> int main(void) { printf("program start\n"); /// 変数宣言 int i=0; /// シリアル通信データ用変数宣言 char sBuf[100]; //char sBuf[1]; //char str[100]; char strT[50] = {0}; char strN[20] = {0}; char strE[20] = {0}; unsigned char flag_data = 0; /// シリアル通信設定用変数宣言 HANDLE hComm; int baudRate = 9600; /// ボーレート9600bps unsigned long nn; DCB dcb; COMMTIMEOUTS cto; ///データ保存用変数宣言 FILE *ofile; errno_t err; /// /// シリアルポートの初期化、オープン /// printf("Open Serial Port\n"); BOOL InitComPort(); hComm = CreateFile( "\\\\.\\COM3", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); /// ポートオープンエラー処理 if ( hComm == INVALID_HANDLE_VALUE ) { printf("Serial Port Open Error!\n"); exit(1); } else {} /// /// シリアルポートの設定 /// printf("Setup Serial Port\n"); GetCommState( hComm, &dcb ); // シリアルポートの状態を取得 dcb.BaudRate = baudRate; SetCommState( hComm, &dcb ); // シリアルポートの状態を設定 GetCommTimeouts( hComm, &cto ); // タイムアウトの設定状態を取得 cto.ReadIntervalTimeout = 1000; cto.ReadTotalTimeoutMultiplier = 0; cto.ReadTotalTimeoutConstant = 1000; cto.WriteTotalTimeoutMultiplier = 0; cto.WriteTotalTimeoutConstant = 0; SetCommTimeouts( hComm, &cto ); // タイムアウトの状態を設定 /// /// シリアルポート通信 /// while(1) { /// /// データ受信 /// /* /// シリアルポートから一文字受信して表示 ReadFile( hComm, sBuf, 1, &nn, 0 ); if(nn != 0) { printf("%c",sBuf[0]); } */ /// シリアルポートから一行受信して表示 memset(sBuf, NULL, sizeof(sBuf)); /// sBufの初期化 ReadFile( hComm, sBuf, sizeof(sBuf), &nn, 0); /// sBufで一行分データを受信 printf("%s", sBuf); /// 受信したデータを表示 for(i=0; i<sizeof(sBuf); i++) { if(sBuf[i] != NULL) { printf("%c", sBuf[i]); } else{} } /// /// 生データの保存 ///      err = fopen_s(&ofile,"puredata.txt","a"); ///"a":追加書き込み専用 if(err != 0)  { printf("ERROR! puredata was not opened\n"); exit(1);  }    else  { while(1) {  ReadFile( hComm, sBuf, 1, &nn, 0 ); // シリアルポートに対する読み込み  printf("%c",sBuf[0]);  if(sBuf[0] != EOF) {  fprintf(ofile,"%c",sBuf[0]); //fprintf(stdout,"%s",str); }  else { printf("\n"); break; } /// /// データ処理 /// /// /// 処理データの保存 /// } printf("program end\n"); return(0); } 出力結果 (例 ※場所特定防止のためGPSがうまく受信されていないパターンを載せています) program start program end $GPRMC,120004.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*7B $GPRMC,120005.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*7A $GPRMC,120006.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*79 $GPRMC,120007.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*78 書き込まれたテキストファイル $GPRMC,120004.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*7B $GPRMC,120005.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*7A $GPRMC,120006.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*79 $GPRMC,120007.000,V,0000.0000,N,00000.0000,E,000.0,000.0,280606,,,N*78 出力してほしい数値は構文の最初のV,後の0000.0000と、そのあとのN,後の00000.0000です。 なるべく生データも別に保存しておきたいので下にある「データ処理」「処理データの保存」の中で処理したいのですが…… 何卒、よろしくお願いします。

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

  • ベストアンサー
回答No.1

strtok() 使えば','区切りで文字列を抽出できるので、 'V'/'N'の直後を取り出せるでしょ。

gmwvmmgm
質問者

お礼

返信が遅くなってしまい申し訳ありませんでした。 strtok()ですか… 盲点でした。 試しにstrtok()を使って if((p = strtok(sBuf,",")) == NULL); if(strcmp(p,"$GPRMC") != 0); /*センテンスの先頭は$GPRMCか?*/ if ((p=strtok(NULL,","))==NULL); /*utc:世界標準時*/ sscanf(p,"%d",&utc); if ((p=strtok(NULL,","))==NULL); /*stat:ステータス*/ stat=p[0]; if ((p=strtok(NULL,","))==NULL); /*lat:緯度*/ sscanf(p,"%lf",&lat); if ((p=strtok(NULL,","))==NULL); /*ns:南北*/ ns=p[0]; if ((p=strtok(NULL,","))==NULL); /*lon:経度*/ sscanf(p,"%lf",&lon); if ((p=strtok(NULL,","))==NULL); /*ew:東西*/ ew=p[0]; と打ち込んでみたところ上手く抜き出すことができました。 ご多忙の中、回答していただきまことにありがとうございました。 ベストアンサーに選ばせていただきます。

関連するQ&A

  • PICとPCでのシリアル通信

    PICとPC間でのシリアル通信を行ってるんですけどうまくいきません。ハイパーターミナル使えばうまくいくんでPIC側のソース(C)はうまくいってると思います。ハイパーターミナルを使わずにシリアルの送受信のプログラム(C++)を組んでるんですけどうまくいかなくて。。。 アドバイスなどお願いします!!どこが違うんでしょうか。。。 ●PC側のソース(C++) #include "stdafx.h" #include <stdlib.h> #include <windows.h> #include<iostream> using namespace std; #define COM_PORT_NAME "COM1" #define BAUD_RATE 9600 #define BYTE_SIZE 8 #define PARITY EVENPARITY #define STOP_BIT TRUE #define F_PARITY ONESTOPBIT HANDLE hComm; // シリアルポートとの通信ハンドル bool ComInit() { // シリアルポートを開ける hComm = CreateFile( COM_PORT_NAME, /* シリアルポートの文字列 */ GENERIC_READ | GENERIC_WRITE, /* アクセスモード:読み書き */ 0, /* 共有モード:他からはアクセス不可 */ NULL, /* セキュリティ属性:ハンドル継承せず */ OPEN_EXISTING, /* 作成フラグ: */ FILE_ATTRIBUTE_NORMAL, /* 属性: */ NULL /* テンプレートのハンドル: */ ); if (hComm == INVALID_HANDLE_VALUE) { printf("シリアルポートを開くことが出来ませんでした。\n"); return false; } // 通信属性を設定する DCB dcb; GetCommState(hComm, &dcb); /* DCB を取得 */ dcb.BaudRate = BAUD_RATE; dcb.ByteSize = BYTE_SIZE; dcb.Parity = PARITY; dcb.fParity = STOP_BIT; dcb.StopBits = F_PARITY; SetCommState(hComm, &dcb); /* DCB を設定 */ return true; } void ComEnd() { // ハンドルを閉じる CloseHandle(hComm); } bool WriteData(char *buff, unsigned int data_size) { DWORD dwWritten; /* ポートへ書き込んだバイト数 */ WriteFile(hComm, buff, data_size, &dwWritten, NULL); if (dwWritten!=data_size) { printf("データの送信に失敗しました。\n"); return false; } return true; } bool ReadData(char *buff, unsigned int max_size) { DWORD dwErrors; /* エラー情報 */ COMSTAT ComStat; /* デバイスの状態 */ DWORD dwCount; /* 受信データのバイト数 */ DWORD dwRead; /* ポートから読み出したバイト数 */ ClearCommError(hComm, &dwErrors, &ComStat); dwCount = ComStat.cbInQue; if (dwCount > max_size) { printf("バッファサイズが足りません。\n"); return false; } ReadFile(hComm, buff, dwCount, &dwRead, NULL); if (dwCount != dwRead) { printf("データの受け取りに失敗しました。\n"); return false; } return true; } int main(int argc, char* argv[]) { char ch; while(1){ cin >> ch; printf("入力 %c\n", ch); ComInit(); WriteData(&ch, strlen(&ch)); ReadData(&ch, strlen(&ch)); ComEnd(); } return 0; }

  • シリアル通信でのデータ受信

    シリアル通信にてデータを連続的に受信するプログラムを つくりたいと思っています. 以下のプログラムを作成して, main関数のcountを増やして,繰り返しreadを行おうとすると, 出力結果として, 時,分,秒,ID,値B,値C,値Dというフォーマットで 0, 9,30, 1,514,708,542,290 0, 9,30, 2,515,707,542,288 0, 9,30, 3,514,709,542,287 0, 9,30, 4,514,707,543,289 0, 9,30, 5,514,708,542,289 0, 9,30, 6,514,708,542,292 0, 9,30, 7,514,708,542,291 0, 9,30, 8,514,708,542,289 0, 9,30, 9,514,708,543, 0, 9,39,35,514,708,542,289 (この後フが連続) フフフフフフフフフフフフフフフ ク 0, 9,39,36,514,708,542,290 0, 9,39,37,515,709,541,291 0, 9,39,38,514,707,542,286 0, 9,39,39,514,708,542,281 0, 9,39,40,514,708,542,284 0, 9,39,41,514,707,542,286 0, 9,39,42,514,707,542,290 0, 9,39,43,514,709,542,290 0, 9,30, 9,514,708,543, 0, 9,39,35,514,708,542,289 フフフフフフフフフ・・・再びフ となってしまいます. 問題としては ・フがたくさんでてきてしまう. ・1サイクルの最後で改行ができていない ・1サイクルが終わって次のサイクルに入る時までの 間にデータが失われている. ・2サイクル目になぜか1サイクル目の値が残っている? などがあります. どなたか解決方法を教えていただけると大変助かります. よろしくお願いします. ------------------------------- #include "stdafx.h" #include <stdlib.h> #include <windows.h> #include <string.h> #include <stdio.h> #define COM_PORT_NAME "COM2" #define BAUD_RATE 57600 #define BYTE_SIZE 5000 //250 #define PARITY NOPARITY //EVENPARITY #define STOP_BIT TRUE #define F_PARITY ONESTOPBIT HANDLE hComm; // シリアルポートとの通信ハンドル bool ComInit() { // シリアルポートを開ける hComm = CreateFile( COM_PORT_NAME, /* シリアルポートの文字列 */ GENERIC_READ | GENERIC_WRITE, /* アクセスモード:読み書き */ 0, /* 共有モード:他からはアクセス不可 */ NULL, /* セキュリティ属性:ハンドル継承せず */ OPEN_EXISTING, /* 作成フラグ: */ FILE_ATTRIBUTE_NORMAL, /* 属性: */ NULL /* テンプレートのハンドル: */ ); if (hComm == INVALID_HANDLE_VALUE) { printf("シリアルポートを開くことが出来ませんでした。\n"); return false; } // 通信属性を設定する DCB dcb; GetCommState(hComm, &dcb); /* DCB を取得 */ dcb.BaudRate = BAUD_RATE; dcb.ByteSize = BYTE_SIZE; dcb.Parity = PARITY; dcb.fParity = STOP_BIT; dcb.StopBits = F_PARITY; SetCommState(hComm, &dcb); /* DCB を設定 */ return true; } void ComEnd() { // ハンドルを閉じる CloseHandle(hComm); } bool ReadData(char *buff, unsigned int max_size) { DWORD dwErrors; /* エラー情報 */ COMSTAT ComStat; /* デバイスの状態 */ DWORD dwCount; /* 受信データのバイト数 */ DWORD dwRead; /* ポートから読み出したバイト数 */ ClearCommError(hComm, &dwErrors, &ComStat); dwCount = ComStat.cbInQue; FILE *fid; fid=fopen("test.txt", "w"); printf("%d %d\n", dwCount, max_size); fprintf(fid,"%d %d\n", dwCount, max_size); fclose(fid); if (dwCount > max_size) { printf("バッファサイズが足りません。\n"); return false; } if(hComm != NULL){ ReadFile(hComm, buff, dwCount, &dwRead, NULL); if (dwCount != dwRead) { printf("データの受け取りに失敗しました。\n"); return false; } } return dwRead; } int main(int argc, char* argv[]) { char buff[BYTE_SIZE]; int count = 0; int data_length; FILE *fid2; fid2=fopen("test2.txt","w"); ComInit(); while(1){ if(count == 2) break; count++; data_length=ReadData(buff, strlen(buff)); printf("%s ",buff); fprintf(fid2, "%s ",buff); } fclose(fid2); ComEnd(); return 0; }

  • シリアル通信の受信待ちについて

    シリアル通信で10Byte受信するまで待ち続けたいのですが、0ByteでReadFileが抜けてしまいます。 ReadFileの最後のパラメタが、NULLならば第3パラメタの値まで待ち続けると思っていたのですが、なにか設定が足りないのでしょうか? タイムアウト値は0にしています。(色々変えて見ましたが同じでした) HANDLE hComm; /* シリアルポートのハンドル */ DCB dcb; char* pszBuf="1234567890"; /* 書込・読込領域 */ hComm = CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); GetCommState(hComm, &dcb); /* DCB を取得 */ dcb.BaudRate = 9600; dcb.ByteSize = 8; dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.ReadIntervalTimeout = 100; dcb.ReadTotalTimeoutMultiplier = 0; dcb.ReadTotalTimeoutConstant = 0; dcb.WriteTotalTimeoutMultiplier = 10; dcb.WriteTotalTimeoutConstant = 500; SetCommState(hComm, &dcb); /* DCB を設定 */ DWORD dwRead; /* ポートから読み出したバイト数 */ ReadFile(hComm, pszBuf, 10, &dwRead, NULL);

  • C++でArduinoをコントロールしたいのですが

    VC++から数値データ(0-100)を送信し、Arduinoに接続されているファンを受信した数値でPWMコントロールしたいのですが、接続を確立したその後からプログラミングの仕方がわかりません。 どのようにしてデータを送信すればよいのでしょうか? 以下のようにして接続を行っています。 //COMポートハンドル HANDLE hComm; hComm = CreateFileA("\\\\.\\COM3", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); //ポートの接続確認 printf("Arduino COM") ; if (hComm == INVALID_HANDLE_VALUE) printf(":not opened\n") ; else{ DCB lpTest; GetCommState(hComm,&lpTest); lpTest.BaudRate = CBR_9600; lpTest.ByteSize = 8; lpTest.Parity = NOPARITY; lpTest.StopBits = ONESTOPBIT; SetCommState(hComm,&lpTest); printf(":OPENED\n") ; WriteFile(hComm, buf,strlen(buf),&write, NULL); } //COMポートハンドルの解放 CloseHandle(hComm); なおArduino側のプログラムは以下のものを使用しています。 //読み取り値の変数 int val=0; void setup(){ //シリアル通信開始 Serial.begin(9600); } void loop(){ //データが0個より多いときの時 if(Serial.available()>0){ //データの読み込み val=Serial.read(); //合図用データ送信(1バイト) Serial.print(65,BYTE); } //アナログ出力(11番ピン)に読み込み値を入れる analogWrite(11,val); }

  • 通信(送信)のプログラム

    bool WriteData(char *buff, unsigned int data_size) {     DWORD dwWritten; /* ポートへ書き込んだバイト数 */ WriteFile(hComm, buff, data_size, &dwWritten, NULL); if (dwWritten!=data_size) { printf("データの送信に失敗しました。\n"); return false; } return true; } 上の関数はシリアル通信の送信する関数なんですが、これに数値などを入れたいんですが、char型のため、一文字しか入れれません。たとえば、01ならchar型の0とchar型の1を別々に送らないとだめなんですが、このようにするしか無理なんでしょうか?int型の数値を好きなように入れて送りたいんですが。あと、OxFFのように16進数も入れれると便利なんですが。駄文ですいません。プログラムの知識が浅はかですいません。

  • シリアル通信プログラム(受信)について

    現在、シリアル通信をする(受信のみ)プログラムを作成しています。 接続先は1秒ごとに10バイトのデータを自動で送信してきます。 現段階でPC側でデータを受信できることは確認できました。 しかし、受信データが文字化け(出力結果が{や■などがでています)しており、その原因がわかりません。 どこが問題なのか教えていただけないでしょうか? また、接続先からは10バイトのうち最初の2バイトは固定の値(0x2b,0x22)がでてくるはずなのですが、それもでてきていません。これも文字化けで見えていないだけでしょうか? 文字化けしても周期的に固定の値に対応した文字がでてくるものだと思ったのですが、でてきていません。 (ソースで50バイトまでみているのはこの周期性を確認するためです) シリアル通信を初めてさわるので、考え方自体間違っているかもしれませんが 配列pszBufに1つずつ、受信された1バイトのデータが格納されていると思っています。 個人的にはprintfでの表記(%cがいけない?)に間違いがあるかと疑っています。 ご回答よろしくお願いいたします。 (環境) Visual C++ 2008 (C/C++) (シリアルポート設定) ボーレート 9600bps パリティ   なし ストップビット 1 データビット 8 (ソース) ※ポートの設定は省略。受信部のみ記述 HANDLE hComm; DWORD dwErrors; COMSTAT ComStat; char pszBuf[1024]; DWORD dwRead; ClearCommError(hComm, &dwErrors, &ComStat); ReadFile(hComm, pszBuf, 50, &dwRead, NULL);  //50バイトまでデータを取得 for(int i=0;i<50;i++){ printf("%c\n",pszBuf[i]); } (参考URL) http://www.geocities.jp/terukat/_geo_contents_/win/comm.html

  • char型をfloat型に変換

    GPSからシリアルポートに流れてくるコンマ区切りのフォーマットをいったんcharにいれて、トークンでぶちぶち切って、違う変数に格納したいです。 流れてくるデータは、 $GPGGA,042449.00,3449.30669291,N,13531.38645000,E,1,4,4.4,81.885,M,34.255,M,,*6D のような数値です。緯度経度や日付等のデータです。 緯度や経度の数値をfloatやdoubleに変換して変数に格納したいのですが、どうしたらよいでしょうか? そのまましたらエラーが出てしまいます。 以下は数値をブチブチ切って表示させるプログラムです。 #include <windows.h> #include <stdio.h> int main(void) { char szSend[] = "$GPGGA,000000.00,0000.00000000,N,00000.00000000,E,0,0,0.0,00.000,M,00.000,M,,*00"; char szBuf[sizeof(szSend)]="$GPGGA,042449.00,3449.30669291,N,13531.38645000,E,1,4,4.4,81.885,M,34.255,M,,*6D"; char *ptr; ptr=strtok(szBuf,","); printf("%s\n",ptr);//$GPGGA ptr=strtok(NULL,","); printf("%s\n",ptr);//時間 ptr=strtok(NULL,","); printf("%s\n",ptr);//緯度 ptr=strtok(NULL,","); printf("%s\n",ptr);//N北 ptr=strtok(NULL,","); printf("%s\n",ptr);//経度 ptr=strtok(NULL,","); printf("%s\n",ptr);//E東 ptr=strtok(NULL,","); ・ ・ ・ ・ return 0; } コンパイラはmicrosoftvisualC++6.0です。 floatとかboubleにしたいのは緯度や経度の数値を計算して扱いやすいデータにするためです。 よろしくお願いします。

  • VC++でrs232c通信

    ハイパーターミナルで試したところ、以下のプログラムにも書いてありますが C,OL,1と入力すると OKという文字が返ってくるというものなのですが、 printf("%s,オンラインに失敗しました\n",l);の所で lがnoneのままでした。 説明書にはC,OL,1[CR][LF]と入力すると OK<CR><LF>またはER,n<CR><LF>と返ってくると書いてありました。 色々調べはしたのですが、わかりません。 根本から間違っているような気もします。 何処が間違っているかご指摘をお願いします。 ************************************* HANDLE COMHandle; DWORD dwRoad,dwWrite,dwError,dwCount; COMSTAT ComStat; char *l="none"; COMHandle=CreateFile("COM3",GENERIC_READ | GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);//ハンドルの取得 if ( COMHandle == INVALID_HANDLE_VALUE ) { printf("COMport Open Error!\n"); getch(); exit(1); } DCB dcb; GetCommState(COMHandle,&dcb);//シリアルポートの状態を取得 dcb.BaudRate=2400;//ボーレート,伝達速度,bps dcb.ByteSize = 8; // データサイズ,bit dcb.Parity = NOPARITY; // パリティ:エラー検出 dcb.StopBits = ONESTOPBIT; // ストップビット SetCommState(COMHandle,&dcb); // シリアルポートの状態を設定 ncf1="C,OL,1\r\n";//入力コマンド WriteFile(COMHandle,ncf1,strlen(ncf1),&dwWrite,NULL); ClearCommError(COMHandle,&dwError,&ComStat); dwCount=ComStat.cbInQue; ReadFile(COMHandle,l,dwCount,&dwRoad,NULL); if(l!="OK\r\n"){ printf("%s,オンラインに失敗しました\n",l); getch(); exit(1); }

  • シリアル通信のポートオープン

    シリアル通信のテストプログラムを作成中でして、一通り動作するようになったのでエラー処理を確認しようとしたところ、存在しないCOMポート?なのにオープンが成功したと処理してしまいます。 環境  P社のノートパソコン  Windows XP Pro SP3  Visual C++6.0 SP6  USB接続のRS-232C変換アダプタを使用  デバイスマネージャでは、拡張ポートはCOM4のみとなっている  ハイパーターミナルの「接続の設定」では、接続方法の選択肢にCOM3とCOM4の2つがある ・COM4を使うと、オープン後、正常に通信できます。 ・COM3を使うと、オープンは出来るが、通信は出来ません。 ソースを記載します。 if(HANDLE_CHECK(m_hComm) == FALSE){ ss.Format("COM%d", m_nRsPort); m_hComm = ::CreateFile(ss, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(HANDLE_CHECK(m_hComm) == TRUE){ dcb.DCBlength = sizeof(DCB); if(::GetCommState(m_hComm, &dcb) != FALSE){ dcb.BaudRate = m_nRsBaudrate; dcb.Parity = m_nRsParity; ・ ・ ・ ・ ・ ・ if(::SetCommState(m_hComm, &dcb) != FALSE){ COM3の場合もCOM4の場合もここを通っている。 } else{ } } } } COM3のオープン時、エラーの検知は出来ないのでしょうか? よろしくお願いします。

  • カレンダーがうまく表示されない

    開始月と終了月を指定して、3か月ごとにカレンダーを改行する プログラムを作ってみました。 ところが、動作をさせてみたところ7月が配列tuki[12]において31日 と指定しているのにも関わらず25日分しか表示されません。 それと、たまに4月分が24日分しか表示されません。(試した限りでは、 4月を終了月に指定するとそうなりました。) なにがおかしいためにこうなってしまうのでしょうか。 よろしくお願いいたします。 #include<stdio.h> #include<string.h> /*月の最初の日をメインプログラムに返す*/ int getyoubi(int year,int month,int day) { if(month==1 || month==2 ) { year--; month +=12; } return ((year+year/4-year/100+year/400+(13*month+8)/5 + day)%7); } /*カレンダーを3か月分表示させる*/ void print(char s[3][7][22],int n) { int i,j; for(i=0;i<n;i++) { printf("%s ",s[i][0]); } printf("\n"); for(i=0;i<n;i++) { printf(" 日 月 火 水 木 金 土 "); } printf("\n"); for(i=0;i<n;i++) { printf("---------------------- "); } printf("\n"); for(i=1;i<7;i++) { for(j=0;j<n;j++) { printf("%s ",s[j][i]); } printf("\n"); } printf("\n"); } int main(void) { int nen1,tuki1,nen2,tuki2,tukiho,nenho,tukih,w,j; char sbuf[3][7][22]; int tuki[12]={31,28,31,30,31,30,31,31,30,31,30,31}; int k; char tmp[4]; int count=0; printf("カレンダーを表示します。\n"); printf("開始年月を入力せよ。\n"); printf("年:"); scanf("%d",&nen1); printf("月:"); scanf("%d",&tuki1); printf("終了年月を入力せよ。\n"); printf("年:"); scanf("%d",&nen2); printf("月:"); scanf("%d",&tuki2); /*最大3カ月分のカレンダーを格納する。*/ do{ w=getyoubi(nen1,tuki1,1); sprintf(sbuf[count][0],"%10d / %02d ",nen1,tuki1); for(k=1;k<7;k++) { sbuf[count][k][0]='\0'; } sprintf(sbuf[count][1],"%*s",3*w,""); k=1; for(j=1;j<=tuki[tuki1-1];j++) { sprintf(tmp,"%3d",j); strcat(sbuf[count][k],tmp); if((j+w-1)%7==6) { k++; } } do{ if((j+w-1)%7==6) { sprintf(sbuf[count][k],"%21s",""); } else { do{ strcat(sbuf[count][k]," "); j++; }while((j+w-1)%7!=0); } k++; }while(k!=7); count++; if(count==3) { print(sbuf,count); count=0; } tuki1++; if(tuki1==13) { tuki1=1; nen1++; } }while(nen1<nen2 || nen1==nen2 && tuki1<=tuki2); if(count) { print(sbuf,count); } return 0; }

専門家に質問してみよう