strtoul関数について

このQ&Aのポイント
  • Atmelマイコンでテンキーパネルのクリックで得られた数値データを使って、パスワードなどの数値と照合して処理を行うプログラムを作成しています。
  • key_buf配列のkey_buf[0]から順に0x30('0')~0x39('9')の文字列の番号が代入されます。
  • strtoul関数の引数に(char *)key_bufを指定することで、配列の要素を文字列として解釈し、それとpassとの比較を行うことができます。
回答を見る
  • ベストアンサー

strtoul関数について

現在Atmelマイコンでテンキーパネルのクリックで得られた数値データを使って、パスワードなどの数値と照合して処理を行うようなプログラムを作成しています。 u8 key_buf[21]; パスワードを1回ごとにクリックしていくとこのkey_buf配列のkey_buf[0]から順に0x30('0')~0x39('9')の文字列の番号が代入されます。 照合したいパスワードデータは u32 pass  というデータ変数でpass = 0x00001234    このようなデータが入っています。 このデータを比較して同一かどうかを調べるために次のようなプログラムを作成しました。 test_id_data = strtoul(key_buf,NULL,10); if(key_index != 0 && test_id_data == pass) {       PASS同一と判定 } しかし、このプログラムではkey_bufの配列がなんであろうとif文条件では全部同一と判定されてしまいます。 試しに、 test_id_data = strtoul((char *)key_buf,NULL,10); if(key_index != 0 && test_id_data == pass) {       PASS同一と判定 } このようにすると、key[0]=0x31,key[1]=0x32,key[2]=0x33,key[3]=0x34 これとpass=0x00001234 は同一と判定して、それ以外だとfalseと分岐されました。 なぜ、(char *)と入れないと意図した動作をしたのかがよくわかりません。 どうぞ、ご教示頂きますよう、お願い致します。

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

  • ベストアンサー
  • wormhole
  • ベストアンサー率28% (1619/5654)
回答No.1

>このようにすると、key[0]=0x31,key[1]=0x32,key[2]=0x33,key[3]=0x34 key_buf[0]=0x31,key_buf[1]=0x32,key_buf[2]=0x33,key_buf[3]=0x34 の書き間違えでしょうか? またstrtoul()に渡す文字列はNUL文字終端である必要があるので key_buf[0]='1',key_buf[1]='2',key_buf[2]='3',key_buf[3]='4',key_buf[4] = '\0' になってるのでしょうか。 また >これとpass=0x00001234 は同一と判定して、それ以外だとfalseと分岐されました。 strtoul()の第3引数が10ですから、"1234"は10進数での1234(16進数でいえば0x4d2)です。 0x00001234と同一と判断されるはずありません。

techhouse
質問者

お礼

回答頂きありがとうございます。 大変申しわけありません。1234は10進数で、16進数では0x000004d2ですね。リアルタイムデバッガでも0x000004d2であることを確認しました。 それと、 keyではなく、key_bufですね。 指摘頂きありがとうございます。

techhouse
質問者

補足

お世話になっております。補足コメント欄にて失礼いたします。 別に(char *)というのを入れなくても問題ないことを確認しました。 test_id_data = strtoul(key_buf,NULL,10); 少し勘違いを起こしていました。助かります。

関連するQ&A

  • xmegaのstrstr関数で文字検索

    現在ATMEL社のATxmega128A1というCPUでプログラミングを行っております。 テンキーパネルでのコマンド操作機能というのを設置しているのですが、テンキー操作で、”#”ボタンが押されると u8 key_proc(u8 * buf,int length) この関数が必ず呼ばれます。 bufという引数に”#”ボタンが押されるまでに押されたボタンのキャラクタデータが収納されたSRAMの番地が格納されています。 例えば、端末の設定などを変更したい場合に使用する4文字のキーがEEPROMに格納されていて、それを変更したい場合のコマンドを追加したいと思っています。 そのEEPROMに格納されている4文字キーというのは (u16)gEnv.main_set.key; というEEPROMに”1234”というデータが入っているのですが、 bufというSRAMのメモリに例えば”1234Z4321#” このようなコマンドが来たらもともと”1234”という現在のkeyと合致して、なおかつ次の文字が”Z”という文字が来たら、次の”4321”というデータに(u16)gEnv.main_set.key;のEEPROMの内容を変更するというプログラムが作りたいと思っています。 現在このようなプログラムでこの機能を実現しています。 #if 1 pass16 = (u16)gEnv.main_set.key; sprintf((char *)str,"%04d",pass16); str[4] = 0; memcpy(value,buf,4); if(strstr((char *)value,(char *)str) != 0) { if(buf[4] == 'Z' && buf[9] == '#') { value[0] = buf[5]; value[1] = buf[6]; value[2] = buf[7]; value[3] = buf[8]; gEnv.main_set.key = strtoul(value,NULL,10); env_save(&gEnv); return true; } } #endif このプログラムを作ったことで疑問に思っていることなのですが、 buf[4] == 'Z' であるかどうかをstrstrとは別のコードで判定しているのですが、 sprintf((char *)str,"%04dZ",pass16); このようなコードで"1234Z"という文字列をstrstr検索して判定することはできないのでしょうか? 現在”sprintf((char *)str,"%04dZ",pass16);”としてしまうと、プログラムが暴走したような状態になり、正常な動作ができなくなってしまう現象が出てしまいます。 どうぞ、ご教示よろしくお願い致します。

  • ファイル

    ファイルを読み込み単語ごとに表示するプログラムです。 例 ファイル データ 形式 歴史・・ のように単語の後には空白がありますファイルです FILE *fp; char buf[1000]; char buf_word[1000]; char *str; char *bufstr; if((fp = fopen("test.txt","r")) == NULL){ printf("error!"); return 0; } while(fgets(buf,1000,fp) !=NULL){ str = buf; while(*str !='\0'){ strbuf = buf_word; if(*str ==' '){ printf("%s",buf_word); } else{ *strbuf++ = *str++; } } } とプログラムしてみましたが*strの値がどうもおかしく 最初が "フ" じゃなく"・"になってます。 最初の単語がG11とかなら"G"になっていますが・・ 教えて下さい。

  • C言語にて構造体のメンバがNULLであるかを判定するサンプルを作成して

    C言語にて構造体のメンバがNULLであるかを判定するサンプルを作成しています。 一応目的の動作はするのですが、プログラミングとして正しいか教えて頂ければと 思います。 <test.c> int main() { /* ---------------------------------------- */ /* 構造体のメンバ(NULL保障無し)がNULLか */ /* 比較するサンプル */ /* ---------------------------------------- */ char buf[50]; /* サンプル構造体 */ struct ST_test { int cd; char name[10]; int no; }; struct ST_test st_test; /* 構造体定義 */ memset(&st_test,0x00,sizeof(st_test)); /* 構造体初期化 */ memset(&buf[0],0x00,sizeof(buf)); /* 構造体初期化 */ /* 構造体に値セット */ st_test.cd = 12; memcpy(&st_test.name[0],"aabbccddee",sizeof(st_test.name)); st_test.no = 999; /* NULL判定 */ if(*st_test.name == 0x00) { printf("NULLです\n"); } else { printf("NULLではないです\n"); } return (0); }

  • C言語で文字列をポインタ名にしたい

    C言語で文字列をポインタ名にしたい 題名のとおりですが、C言語で文字列をポインタ名にする方法はありますか? 具体的にはxの配列の個々の要素を、計算回数による計算結果の推移をファイルに出力したいと考えています。 ファイル名は「test_x_1.data」、「test_x_2.data」、…「test_x_50.data」のようになっています。 (要素分のファイルを作成するということです。) ここでそれぞれの「test_x_1.data」、「test_x_2.data」、…「test_x_50.data」には、 x[i]の計算回数と計算結果が格納されていますが、 現状では、fopenとfcloseを計算回数分繰り返しているため、計算時間がかかってしまっています。 よって、計算を行う前の最初にfopen、最後にfcloseを行うようにしたいのですが、 ファイルポインタを開く作業を手動で行うと、xの要素分ファイルポインタを用意しなくてはならなくなります。 (現状のようにファイルポインタを使いまわすのではなく、 要素分(=ファイル数)のファイルポインタを、常に開きっぱなしにしたいということです。) そのため、文字列をポインタ名にすることで、その作業を自動で行えるようにできればと考えています。 実際にchar型の配列が文字列になっているため、「FILE *buf」のように宣言しようと試みたのですが、 bufは既に文字列型の配列として宣言されているため、使用することができませんでした。 (文字列そのものをファイルポインタ名にできなくても、 この場合、要素数分のファイルポインタを自動で用意できれば問題ないのですが…) 下は簡単なプログラム例です。詳しい方のご助言を戴ければ幸いです。 よろしくお願い致します。 -------------------------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> #include <math.h> #define CAL 10000 /*計算回数*/ #define ELE 50 /*配列の要素数*/ #define NUM_CHAR 20 /*char型で確保する文字数*/ int i,j,n; /*forループ用*/ double x[ELE]; /*計算結果の配列*/ char buf[ELE][NUM_CHAR]; /*文字列*/ int main(void){ char filename[] = "test_x_"; char fileext[] = ".data"; /*「test_x_数字.data」という文字列の出力*/ for(i=0;i<ELE;i++){ sprintf(buf[i],"%s-I%d%s",filename,i,fileext); } for(n=1;n<CAL;n++){ /*計算部分*/ for(i=0;i<ELE;i++){ x[i] = 2*n+i; } /*ファイルに出力*/ for(i=0;i<ELE;i++){ FILE *fp; /*このファイルポインタ名を要素数分用意したい*/ if(n==1){ if((fp = fopen(buf[i],"w"))==NULL){ printf("The program can't create a file. : buf[i] \n"); exit(1); } } if(n>=2){ if((fp = fopen(buf[i],"a+"))==NULL){ printf("The program can't read a file. : buf[i] \n"); exit(1); } } fprintf(fp,"%d %f\n",i,x[i]) fclose(fp); } } return 0; } --------------------------------------------------------------------------------

  • 関数化

    #include <ctype.h> #include <string.h> #include <stdlib.h> void swap(char p[], char q[]); char *get(char *str, char buf[], int line, int field); typedef struct { int number; char *class_type; char* name; char *subject; } my; my *data; int main(int argc, char* argv[]) { FILE *fp; int field = 0, line = 0; char buf[1000], *str; char *bufG; int line2 = 0; if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } while(fgets(buf, 1000, fp) != NULL){ line2++; } fclose(fp); printf("%d\n", line2); if((fp=fopen("test3.csv","r"))==NULL){ printf("ファイルが開けません"); } data = (my *)malloc(sizeof(my) * line2); while(fgets(buf,1000,fp) != NULL){ str = buf; while(*str != '\0'){ bufG = get(str, buf, line, field); switch(field){ case 0: data[line].number = atoi(bufG); break; case 1: data[line].class_type = (char *)malloc(strlen(bufG) +1); strcpy(data[line].class_type, bufG); break; case 2: data[line].name = (char *)malloc(strlen(bufG) + 1); strcpy(data[line].name, bufG); break; case 3: data[line].subject =(char *)malloc(strlen(bufG) + 1); strcpy(data[line].subject, bufG); break; } str++; field++; } line++; field = 0; } fclose(fp);     for(int m = 1; m < line; m++){ printf("%d\n", data[m].number); printf("%s\n", data[m].class_type); printf("%s\n", data[m].name); printf("%s\n", data[m].subject);     } return 0; } char *get(char *str, char buf[], int line, int field) { char bufG[1111]; int i; for(i = 0; *str != ',' && *str != '\0' ; i++){ if(*str == '\n'){ bufG[i] = '\0'; } else{ bufG[i] = *str; } str++; } bufG[i] = '\0'; return bufG; } 前回の質問 http://okwave.jp/qa5094929.html で提示していただいたサンプルの関数化をはかりましたが うまくいきません。これを実行すると1しか表示されません。 原因はおそらくポインタだと思いますがどうすればいいのか わかりません。教えて下さい。bufを引数にする意味ないのでは という意見は今の所はとりあえずなしで fieldの値によってbufGが色々とってくる。 例えば1,A,山田,数学の場合 field = 0のときbufGは1 filed=1のときbufGはA field=2のときbufGは山田 filed=3のときbufGは数学という ような値が返ってくるようにしたいです。

  • Cで二次元配列の読み込み

    はじめまして。 hiraです。 今非常に基本的であろうことに悩んでいます。まだまだプログラムを始めたところなのでうまくいきません。 内容は・・・ あるファイルを読み込んで、二次元の配列に格納していく。 です。 具体的には test.txtというファイルがあり、中身は数字の二次元配列です。 カンマやtabで区切られています。配列の大きさ、数字の桁数などはファイルによって違います。 そのファイルを読み込んで、配列に格納したいと考えています。 今は一列を読み込むことには成功しています。そこからどのようにして分けて言ったらいいのか・・・ご教示お願いします。 もしくは、もっと違う方法で読み込む方法があればよろしくお願いします。 #include <stdio.h> #include <stdlib.h> int main(void) { FILE *fin; char array[256]; char buf[256]; fin=fopen("test.txt","r"); if(fin == NULL){ printf("%sがオープンできません\n",fin); exit(1); } while(fgets(buf,256,fin) != NULL) {           ここが問題・・・ } fclose(fin); return 0; }

  • 強制終了されていまいます。

    標準入力された1行を"<"から">"までと文字のところにわけるプログラムを書いたのですが、コンパイルして実行して入力すると、画面が黒くなって止まってしまいます。以下のところが問題の部分だと思うんですが、理由がわかりません。よろしくお願いします。 while(fgets(buf, 1024, stdin) != NULL){ i = 0; j = 0; while(buf[i] != '\n' || buf[i] != '\0'){ if ((x = (char *)malloc(sizeof(char))) == NULL){ printf("malloc error\n"); exit(1); } if(buf[i] == '<'){ j = i; while(buf[j] != '>'){ j++; } strncpy(x, &buf[i], j-i+1); i = j + 1; x[strlen(x)] = '\0' putRear(deq, x); } else if(isalpha(buf[i])){ j = i; while(buf[j] != '>'){ j++; } strncpy(x, &buf[i], j-i); i = j + 1; x[strlen(x)] = '\0'; putRear(deq, x); } } }

  • MYSQLへのデータサイズの大きなデータの挿入

    C APIを用いて、MYSQLにテキストファイルの中身を格納したいと考えています。 以下のプログラムのように一度ファイルの中身をchar型配列に書き出し、配列の中身をクエリにコピーというようにすると、ファイルの大きさに合わせて、非常に大きな配列を確保しなければならないと思います。 int main(void){ MYSQL mysql; char query[1000]; char buf[1000]; FILE *fp; fp = fopen("test.txt", "r"); mysql_init(&mysql); if(!mysql_real_connect(&mysql,ホスト名,ユーザ名,パスワード,DB名,0,NULL,0)){ //エラー処理 } fread(buf, sizeof(char), sizeof(buf), fp ); sprintf(query, "insert into DB名 values(buf)); mysql_real_query(&mysql, query, strlen(query)); } これではメモリの無駄遣いなので、他の方法として、 1.データを分割して複数回に分けて挿入する 2.テキストファイルから直接読み込む を考えました。 しかし 1.は方法が分からず、 2.はリダイレクトを使えばできると思ったのですが、リダイレクトでは  テキストファイルにSQLコマンドも記入しておく必要があると思うの で、今回の方法には合いません。 MYSQLのフィールドにC言語から大きいデータを書き込むよい方法があれば教えてください。さらには、読み出し方まで教えていただけると助かります。 よろしくお願い致します。

    • ベストアンサー
    • MySQL
  • 指定した文字列を探して・・・

        第1引数の文字列中に第2引数で指定した文字がある場合に、その     文字のあるアドレス(ポインタ)を返す関数doko()作成し、     プログラムを完成させよ。     指定した文字がない場合はNULL(ヌルポインタ)を返すものとする。     配列の[](カギカッコ)を利用しないで作る事     main内は変えないこと いろいろと模索したのですが、strcpyなどは使うのでしょうか? 参考サイトを見たりしたり、ほかの質問などを見たのですが なかなか理解できずに現在にいたってます 以下のコードのdokoは沢山やりすぎたので一番シンプルな間違い方をしています 何かご指摘あればお願いします #include <stdio.h> #define MAX 128 char* doko(char *,char); int main() { char buf[MAX]; char *p = "abcdef12345"; char *r; r = doko(p, 'f'); if (r == NULL) { printf("mojiretsu ni f toiu moji ha arimasen\n"); return 0; } printf("%s (= f12345)\n", r); scanf("%s", buf); r = doko(buf, 'x'); if (r == NULL) { printf("mojiretsu ni x toiu moji ha arimasen\n"); return 0; } printf("%s\n", r); return 0; } char* doko(char *p,char a) { while(*p){ if(*p == a){ return p; } if(*p != a){ return NULL; } ++p; } }

  • ライブラリ関数について教えてください

    C言語を独学で勉強しています。 ファイルの中のデータと配列データが一致するかを調べるプログラムを作ろうとしています。 しかし、私が作っているプログラムでは表示結果が正しくありません。 char型では==を使って一致かどうかを調べることが出来ないので、ライブラリ関数を使う必要があることを知ったのですが、調べてもよくわかりませんでした・・・ どのように作ればいいのか詳しく教えていただけないでしょうか。 よろしくお願いします。 #include<stdio.h> struct test { char no[5]; char name[10]; char english[5]; char math[5]; }; int main(void){ FILE *fp; int i; char f_no[5], f_name[5]; struct test data[5] = { {"001","akemi","100","40"}, {"002","tadao","59","76"}, {"003","mika","94","69"}, {"004","hiroshi","54","98"}, {"005","kazu","39","57"} }; struct test *test_p; test_p = data; if ((fp = fopen("test.txt", "r")) == NULL) { printf("NOT OPEN FILE\n"); } else { while (fscanf(fp, "%s%s", f_no, f_name) == 2) { for(i = 0; i<=5; i++) { if((test_p->no == f_no) && (test_p->name == f_name)) { printf("%s %s 英語%s 数学%sです。\n", f_no, f_name, test_p->english, test_p->math); } else { printf("%s %s 一致しません\n", f_no, f_name); break; } ++test_p; } } } fclose(fp); }

専門家に質問してみよう