C フォームから受け取った知をクッキーで発行 2

このQ&Aのポイント
  • フォームから受け取った情報をクッキーに保存する方法について解説します。
  • クッキーが存在しない場合にエラーが発生する問題と、文字列の分解がうまくいかない問題について解決策を教えてください。
  • また、ソースコードの中ではフォームデータの取得やクッキーの取得や設定、HTMLの表示などの処理が行われています。
回答を見る
  • ベストアンサー

C フォームから受け取った知をクッキーで発行 2

前回 http://okwave.jp/qa/q7765400.html からあれこれしてフォームの値をクッキーに保存できるようになったのですが、バグが出てきました。 一、クッキーが存在しないとエラーが出る ニ、Deta1関数を使って文字列の分解を試みるもうまく分解されない この2つのバグを解決するにはどうしたら直せますか? ---以下ソース--- #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> char *nameset[2],*valueset[2]; char *nameset2[2],*valueset2[2]; int Deta1(char *a,int b); int Dcd(char *set,int a); void get_Form(void); void get_cookie(void); void set_cookie(void); int hen(char *buf, char *mae, char *ato); void Page(int mode); int main(void) { char *nameset[2],*valueset[2]; char *nameset2[2],*valueset2[2]; printf("Content-type: text/html\n"); get_Form(); set_cookie(); get_cookie(); printf("\n"); Page(0); } int Deta1(char *a,int b){ int i=0,cn=0; if(a[0]==NULL){ return(-1); } nameset[0]=a; while((a[++i]!=NULL)&&(i<b)){ /* 項目の分解 */ if(a[i]=='='){ a[i]=NULL; valueset[cn]=a+i+1; } /* データ項目で分解 */ else if(a[i]=='&'){ a[i]=NULL; cn++; nameset[cn]=a+i+1; } } return cn+1; } int Dcd(char *set,int a){ int i,j; char buf,*tmp; if(a==0){ return -1; } tmp=(char*)malloc(a); for(i=0,j=0;i<a;i++,j++){ if(set[i]=='+'){tmp[j]=' ';continue;} if(set[i]!='%'){tmp[j]=set[i];continue;} if(set[++i]>='A'){buf=set[i]-'A'+10;} else{buf=set[i]-'0';} buf*=16; if(set[++i]>='A'){buf+=set[i]-'A'+10;} else{buf+=set[i]-'0';} tmp[j]=buf; } for(i=0;i<j;i++){ set[i]=tmp[i]; } set[i]='\0'; free(tmp); return 0; } void get_Form(void){ int a=0; int i=0; char *chr=NULL; if ( getenv("CONTENT_LENGTH")!=NULL ){ a = atoi( getenv("CONTENT_LENGTH") ); } chr=(char *)malloc(a+1); scanf("%s",chr); chr[a] = '\0'; if (a==0){ return ; } int deta1=Deta1(chr,a); } void get_cookie(void){ int i=0,cn=0; int a=NULL; char *b; if( (getenv("HTTP_COOKIE"))!=NULL){ a=strlen(getenv("HTTP_COOKIE")); } if(a==NULL){ } b=getenv("HTTP_COOKIE"); while((b[++i]!=NULL)&&(i<a)){ if(b[i]=='='){ b[i]=NULL; nameset2[0]=b+i+1; } /* 項目の分解*/ if(b[i]=='-'){ b[i]=NULL; valueset2[cn]=b+i+1; } /*データ項目で分解*/ else if(b[i]=='&'){ b[i]=NULL; cn++; nameset2[cn]=b+i+1; } } for(i=0;i<cn+1;i++){ Dcd(nameset2[i],strlen(nameset2[i])); Dcd(valueset2[i],strlen(valueset2[i])); } } void set_cookie(void) { time_t timer; struct tm *tset; char expires[256]; char *name="sskchat"; int kikan=86400*90; char *set[2]; int i; for(i=0;i<2;i++){ set[i]=NULL; } for(i=0;i<2;i++){ set[i]=valueset[i]; } for(i=0;i<2;i++){ if(set[i]==NULL){ set[i]="no"; } } timer = time(NULL); timer += kikan; tset = gmtime(&timer); strftime(expires, 255, "%a, %d-%b-%Y %H:%M:%S GMT", tset); printf("Set-Cookie:%s=name-%s&mail-%s; expires=%s;\n",name,set[0],set[1],expires); } void Page(int mode){ FILE *fp; char *f1="!name!",*h1; char *f2="!mail!",*h2; if(valueset2[0]==NULL||strcmp("!name!",valueset2[0])==0){ h1=""; } else{ h1=valueset2[0]; } if(valueset2[1]==NULL||strcmp("!mail!",valueset2[1])==0){ h2=""; } else{ h2=valueset2[1]; } char buf[200]; char set[200]; fp = fopen("ren.html", "r+"); while( fgets( set, 200, fp ) != NULL ){ strcpy(buf,set); while(hen(buf, f1, h1)); while(hen(buf, f2, h2)); printf("%s", buf); } fclose(fp); } int hen(char *buf, char *mae, char *ato){ char *nw; size_t zen,go; zen = strlen(mae); go = strlen(ato); if(zen == 0 || (nw = strstr(buf, mae)) == NULL){ return 0; } memmove(nw + go, nw + zen, strlen(buf) - (nw + zen - buf ) + 1); memcpy(nw, ato, go); return 1; } ---ソースここまで--- ---ren.htmlの内容--- <form action="first.exe" method="post"> 名前:<input type="text" name="name" size="100" value="!name!"><br><br> メール:<input type="text" name="mail" size="100" value="!mail!"><br><br> 本文:<textarea name="text" cols="70" rows="10"></textarea><br><br> <input type="submit" value=" 送 信 "><br> </form>

  • CGI
  • 回答数2
  • ありがとう数1

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

  • ベストアンサー
  • ralf124c
  • ベストアンサー率52% (232/446)
回答No.2

質問1 httpヘッダ出力パート ---------------------------------------- printf("Content-type: text/html\n"); get_Form(); set_cookie(); get_cookie(); printf("\n"); ---------------------------------------- の ---------------------------------------- set_cookie(); get_cookie(); ---------------------------------------- が"×"です。 クッキーの設定はhttpヘッダから可能ですが、参照は環境変数を介する必要があります(ソースコードもそうなってるはずですが)。 環境変数はクライアントからWebサーバに対して「CGIを介したプログラム」の起動オーダーが発生した際に、その実行プロセスの環境を構成するためにプロセス起動時に作り上げられるものです。(注:CGIはプログラムのことでは有りません。Webを介してプログラムを起動する仕組み→インターフェース:Common Gateway Interface のことです。だから標準入出力機能を持った言語なら何でもOKなのです。) クッキーセット直後、同一プロセスからクッキーの環境変数を参照することは無意味です。クッキーはブラウザ側に送られても、環境変数はサーバ側にあって自動更新はされません。CGIプロセスの途中でサーバ側からクライアントのデータぶっこ抜き放題ならセキュリティもクソもあったもんじゃないでしょう。 あくまでも「クライアントの指示」でサーバ側のプロセス開始オーダーがあったときのみ必要なデータをクライアント側が送信し、サーバはそこからプロセスに必要なデータから環境変数群を構成してプログラムを開始するのです。 セットしたクッキーを参照したいなら、そのプロセス終了後に新たなプロセス(プログラムを別にする)で参照するしかないでしょう。 要するにクッキーを食わせるプログラムと、クッキーを参照するプログラムは分けて起動すること。 あと「サーバサイドのプログラムまたはプロセス」と「クライアントサイドのプログラムまたはプロセス」の区別をつけて考えることです。 さらに、HTTPをはじめとするTCP/IPについてもプロトコルとは何ぞや程度は・・・。 C/Sやネットプログラミングに限らず言語だけ知ってても仕組みを知らんと実装はなかなか難しいということですね。 質問2 関数「Data1」が挙動不審なので作り直してみました。 nameset[0]に全POSTデータを入れた後、共通のポインタから直にいじり倒しているので最終的にvaluesetの最後と同じになっています。 最適化はしてないので教科書みたいなリスト(しかも古いスタイル)になりますが・・・ --------------------------------------------------------- int Deta1(char *a,int b){  int i,nMax;  char *aTmp[30]; /* とりあえず30個まで耐えられるように */  char *sTmp,*sSTW;  sTmp = a;  i=0;  while((aTmp[i] = strtok(sTmp, "&")) != NULL){   sTmp = NULL;   i++;  }  nMax = i;  for(i=0; i < nMax; i++){   sSTW = aTmp[i];   nameset[i] = strtok(sSTW, "=");   valueset[i] = strtok(NULL, "=");  }  return nMax; } --------------------------------------------------------- インデントは全角にしてるのでコピペ時には注意 できれば関数名は別のを考えたほうがいいと思う。代入する変数名とかぶってるし。 あと、評判の悪いstrtok使ってるけど、この処理って基本半角文字だけだから適材適所ってことで できれば値はエンコードされてるはずだからデコードして出したほうが理にかなってるかも こんな感じで答えになってるかな・・・。 それにしても、あらためてCの文字列・配列処理は読み書きがめんどくさくて歳を感じてしまいました。 perlで作ったほうが開発効率いいと思う。 正規表現の変態さ加減なんかはもう・・・。

nanaka2222
質問者

お礼

あれから作ってみて完全にバグを取り除けましたので同じ様な疑問をもった人のために書き込んでおきます。 (どうかけばいいか探してもグーグルで検索した時に見つからなかったため) これでちゃんとしたチャットや掲示板が作れる♪ ---ソースの内容--- #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> char *nameset[3],*valueset[3]; char *nameset2[2],*valueset2[2]; int Deta1(char *a,int b); int Dcd(char *set,int a); void get_Form(void); void set_cookie(void); void get_cookie(void); int hen(char *buf, char *mae, char *ato); void Page(void); void main(void){ printf("Content-type: text/html\n"); get_Form(); if(valueset[0]!=NULL){ set_cookie(); } get_cookie(); printf("\n"); Page(); } int Deta1(char *a,int b){ int i=0,cn=0; if(a[0]==NULL){ return(-1); } nameset[0]=a; while((a[++i]!=NULL)&&(i<b)){ /* 項目の分解 */ if(a[i]=='='){ a[i]=NULL; valueset[cn]=a+i+1; } /* データ項目で分解 */ else if(a[i]=='&'){ a[i]=NULL; cn++; nameset[cn]=a+i+1; } } return cn+1; } int Dcd(char *set,int a){ int i,j; char buf,*tmp; if(a==0){ return -1; } tmp=(char*)malloc(a); for(i=0,j=0;i<a;i++,j++){ if(set[i]=='+'){tmp[j]=' ';continue;} if(set[i]!='%'){tmp[j]=set[i];continue;} if(set[++i]>='A'){buf=set[i]-'A'+10;} else{buf=set[i]-'0';} buf*=16; if(set[++i]>='A'){buf+=set[i]-'A'+10;} else{buf+=set[i]-'0';} tmp[j]=buf; } for(i=0;i<j;i++){ set[i]=tmp[i]; } set[i]='\0'; free(tmp); return 0; } void get_Form(void){ int a=0; char *chr=NULL; if ( getenv("CONTENT_LENGTH")!=NULL ){ a = atoi( getenv("CONTENT_LENGTH") ); } chr=(char *)malloc(a+1); scanf("%s",chr); chr[a] = '\0'; if (a==0){ return; } int deta1=Deta1(chr,a); } void set_cookie(void) { time_t timer; struct tm *tset; char expires[256]; char *name="sskchat"; int kikan=86400*90; char *set[2]; int i; for(i=0;i<2;i++){ set[i]=valueset[i]; } timer = time(NULL); timer += kikan; tset = gmtime(&timer); strftime(expires, 255, "%a, %d-%b-%Y %H:%M:%S GMT", tset); printf("Set-Cookie:%s=name-%s&mail-%s; expires=%s;\n",name,set[0],set[1],expires); } void get_cookie(void){ int i=0,cn=0; int a=NULL; char *b; if((getenv("HTTP_COOKIE"))!=NULL){ a=strlen(getenv("HTTP_COOKIE")); b=getenv("HTTP_COOKIE"); while((b[++i]!=NULL)&&(i<a)){ if(b[i]=='='){ b[i]=NULL; nameset2[0]=b+i+1; } /* 項目の分解*/ if(b[i]=='-'){ b[i]=NULL; valueset2[cn]=b+i+1; } /*データ項目で分解*/ else if(b[i]=='&'){ b[i]=NULL; cn++; nameset2[cn]=b+i+1; } } } for(i=0;i<4;i++){ if(nameset[i]!=NULL){ Dcd(nameset[i],strlen(nameset[i])); } if(valueset[i]!=NULL){ Dcd(valueset[i],strlen(valueset[i])); } if(nameset2[i]!=NULL){ Dcd(nameset2[i],strlen(nameset2[i])); } if(valueset2[i]!=NULL){ Dcd(valueset2[i],strlen(valueset2[i])); } } } void Page(void){ FILE *fp; char buf[200]; char *f1="!name!",*h1=""; char *f2="!mail!",*h2=""; if((valueset[0]==NULL)&&(valueset2[0]!=NULL)){ h1=valueset2[0]; } if(valueset[0]!=NULL){ h1=valueset[0]; } if((valueset[1]==NULL)&&(valueset2[1]!=NULL)){ h2=valueset2[1]; } if(valueset[1]!=NULL){ h2=valueset[1]; } fp = fopen("ren.html", "r+"); while( fgets( buf, 200, fp ) != NULL ){ while(hen(buf, f1, h1)); while(hen(buf, f2, h2)); printf("%s", buf); } fclose(fp); } int hen(char *buf, char *mae, char *ato){ char *nw; size_t zen,go; zen = strlen(mae); go = strlen(ato); if(zen == 0 || (nw = strstr(buf, mae)) == NULL){ return 0; } memmove(nw + go, nw + zen, strlen(buf) - (nw + zen - buf ) + 1); memcpy(nw, ato, go); return 1; } ---ren.htmlの内容--- <html> <head> <title>フォーム</title> </head> <body> <form action="first.exe" method="post"> 名前:<br><input type="text" name="name" size="100" value="!name!"><br><br> メール:<br><input type="text" name="mail" size="100" value="!mail!"><br> 本文:<br><textarea name="text" cols="70" rows="10"></textarea><br><br> <input type="submit" value=" 送 信 "><br> </form> </body> </html>

nanaka2222
質問者

補足

<<クッキーセット直後、同一プロセスからクッキーの環境変数を参照することは無意味です。クッキーはブラウザ側に送られても、環境変数はサーバ側にあって自動更新はされません。CGIプロセスの途中でサーバ側からクライアントのデータぶっこ抜き放題ならセキュリティもクソもあったもんじゃないでしょう。 あくまでも「クライアントの指示」でサーバ側のプロセス開始オーダーがあったときのみ必要なデータをクライアント側が送信し、サーバはそこからプロセスに必要なデータから環境変数群を構成してプログラムを開始するのです。 セットしたクッキーを参照したいなら、そのプロセス終了後に新たなプロセス(プログラムを別にする)で参照するしかないでしょう。 私のプログラムでおかしなところはまさしくこれですかね 何度かバグらせまくってなんとなく感じてはいましたがはっきり形を教えていらだけましてありがとうございました 問題は方法が分かってもどのように書けばいいか分からない事ですね <<あと「サーバサイドのプログラムまたはプロセス」と「クライアントサイドのプログラムまたはプロセス」の区別をつけて考えることです。 その区別すら分かっていないので調べる必要がありそうですね <<科書みたいなリスト(しかも古いスタイル)になりますが・・ 教科書みたいな書き方は非常にありがたいです 是非参考にさせていただきます ありがとうございました <<あと、評判の悪いstrtok使ってるけど、この処理って基本半角文字だけだから適材適所ってことで できれば値はエンコードされてるはずだからデコードして出したほうが理にかなってるかも ああ、なにやら扱いにくいと感じたのはそういう理由ですか ちゃんと扱えれば動かせるはずだと思って使ってました <<perlで作ったほうが開発効率いいと思う。 正規表現の変態さ加減なんかはもう・・・ 皆さんそういわれますが最終的に戦略シュミレーションのブラウザゲームを作りたいのでperlではちょっと・・・。 といった理由なのでperlは使う気がないのですよ ごめんなさいね

その他の回答 (1)

  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.1

こまかく追い掛けてないけど ・getenvしたポインタの先をそのまま変えちゃって大丈夫? ・mallocとfreeは対になってますか? ・次のものが、 グローバルなものと、main関数ローカルなものがあるけど、Data2関数でグローバルを変えて、それをmain関数内でローカルの方でチェックした、とかないですか? char *nameset[2],*valueset[2]; char *nameset2[2],*valueset2[2]; あと、エラーにはならないだろうけど、厳密には、NULLと'\0'は違います。

nanaka2222
質問者

補足

・getenvしたポインタの先をそのまま変えちゃって大丈夫? おそらくは・・・・ ・mallocとfreeは対になってますか? なっているはずです(ミスってなければ) ・次のものが、 グローバルなものと、main関数ローカルなものがあるけど、Data2関数でグローバルを変えて、それをmain関数内でローカルの方でチェックした、とかないですか? char *nameset[2],*valueset[2]; char *nameset2[2],*valueset2[2]; そういえばおかしな処理していました 教えていただきありがとうございました

関連するQ&A

  • C フォームから受け取った値をクッキーで発行

    (C言語)フォームから受け取った値をクッキーで発行するにはどのようにするのでしょうか? 問題として ・フォームから値を受け取る事は出来てもクッキーが発行できない もしくは ・フォームから値を受け取れないのにクッキーは発行できる のどっちかしか出来ないため困りました。 どうすればフォームから受け取った値をクッキーで発行できますか? ---以下ソース--- #include <stdio.h> #include <stdlib.h> #include <string.h> int Deta1(char *a,int b,char *nameset[],char *valueset[]); int Dcd(char *set,int a); int get_cookie(char *a,int b,char *nameset2[],char *valueset2[]); void set_cookie(char *valueset[]); void main(void){ int i; int a=0; char *chr=NULL; char *nameset[7]; char *valueset[7]; char *nameset2[7],*valueset2[7]; int b=200; int mode=0; char *ss=getenv("HTTP_COOKIE"); for(i=0;i<7;i++){ nameset2[i]=NULL; valueset2[i]=NULL; } printf("content-type: text/html\n"); //set_cookie(valueset); //ここでset_cookie関数を呼び出せばクッキーは発行出来るけれどフォームに入力された値が入らない printf("\n"); if(mode==0){ //省略しますがフォームで7つの項目があると思ってくださいね if ( getenv("CONTENT_LENGTH")!=NULL ){ a = atoi( getenv("CONTENT_LENGTH") ); } chr=(char *)malloc(a+1); scanf("%s",chr); chr[a] = '\0'; if (a==0){ return ; } printf("%s<br>",chr); int deta1=Deta1(chr,a,nameset,valueset); for(int i = 0;i<deta1;i++){ Dcd(nameset[i],strlen(nameset[i])); Dcd(valueset[i],strlen(valueset[i])); } for(i=0;i<7;i++){ printf("%s %s<br>",nameset[i],valueset[i]); } //set_cookie(valueset); //ここでset_cookie関数を呼び出せばフォームが入力された値が入るけれどクッキーは発行できない int deta2=get_cookie(ss,b,nameset2,valueset2); for(i=0;i<7;i++){ printf("%s %s<br>\n",nameset2[i],valueset2[i]); } free((void *)chr); } else if(mode==1){ //省略 } else{ //省略 } } int Deta1(char *a,int b,char *nameset[],char *valueset[]){ int i=0,cn=0; if(a[0]==NULL){ return(-1); } nameset[0]=a; while((a[++i]!=NULL)&&(i<b)){ if(a[i]=='='){ a[i]=NULL; valueset[cn]=a+i+1; } else if(a[i]=='&'){ a[i]=NULL; cn++; nameset[cn]=a+i+1; } } return cn+1; } int Dcd(char *set,int a){ int i,j; char buf,*tmp; if(a==0){ return -1; } tmp=(char*)malloc(a); for(i=0,j=0;i<a;i++,j++){ if(set[i]=='+'){tmp[j]=' ';continue;} if(set[i]!='%'){tmp[j]=set[i];continue;} if(set[++i]>='A'){buf=set[i]-'A'+10;} else{buf=set[i]-'0';} buf*=16; if(set[++i]>='A'){buf+=set[i]-'A'+10;} else{buf+=set[i]-'0';} tmp[j]=buf; } for(i=0;i<j;i++){ set[i]=tmp[i]; } set[i]='\0'; free(tmp); return 0; } int get_cookie(char *a,int b,char *nameset2[],char *valueset2[]){ int i=0,cn=0; if(a==NULL){ return(-1); } while((a[++i]!=NULL)&&(i<b)){ if(a[i]=='='){ a[i]=NULL; nameset2[0]=a+i+1; } if(a[i]=='-'){ a[i]=NULL; valueset2[cn]=a+i+1; } else if(a[i]=='&'){ a[i]=NULL; cn++; nameset2[cn]=a+i+1; } } return cn+1; } void set_cookie(char *valueset[]){ time_t timer; struct tm *tset; char expires[256]; char *name="sskchat"; int kikan=86400*90; char *set[7]; int i; for(i=0;i<7;i++){ set[i]=valueset[i]; } for(i=0;i<7;i++){ if(set[i]==NULL){ set[i]="no"; } } timer = time(NULL); timer += kikan; tset = gmtime(&timer); strftime(expires, 255, "%a, %d-%b-%Y %H:%M:%S GMT", tset); printf("Set-Cookie:%s=mode-%s&name-%s&mail-%s&hp-%s&cc-%s&gyo-%s&zkou-%s; expires=%s;\n",name,set[0],set[1],set[2],set[3],set[4],set[5],set[6],expires); } ---ソースここまで---

    • ベストアンサー
    • CGI
  • 文字列を分解して特定の項目を別の変数に

    文字列を分解して特定の項目を別の変数に入れたいのですが、条件式を満たさないので別の変数に入れれません 下にソースを書くのですが age の項目だけ別の変数に入れたいのです どのようにすれば入れれますか? #include <stdio.h> #include <string.h> char *nameset[12],*valueset[12]; char *nameset3[12],*valueset3[12]; void main(void){ int c=0; int i=0,cn=0,dn=0; char *tm=NULL; char *han; char *a="name=miku&age=15&like=momo"; int b=strlen(a); nameset[0]=a; while((a[++i]!=NULL)&&(i<b)){ /* 項目の分解 */ if(a[i]=='='){ a[i]=NULL; if(c!=1){ valueset[cn]=a+i+1; cn++; } else{ valueset3[dn]=a+i+1; dn++; c=0; } } /* データ項目で分解 */ else if(a[i]=='&'){ a[i]=NULL; han=a+i+1; if(strcmp(han,"age")==0){ nameset3[dn]=han; c=1; } else{ nameset[cn]=han; } } } printf("%s\n", nameset[0]); printf("%s\n", valueset[0]); printf("%s\n", nameset[1]); printf("%s\n", valueset[1]); printf("%s\n", nameset[2]); printf("%s\n\n", valueset[2]); printf("%s\n", nameset3[0]); printf("%s\n", valueset3[0]); }

  • 文字列を分割して変数に格納したい

    文字列を分割して変数に格納したいのですがうまくいきません。 ---以下ソース--- #include <stdio.h> #include <string.h> void main(void){ char tai[]="name1=value1&name2=value2&name3=value3&name4=value4"; char *tp; int a; int b; int i; int co=0; a=strlen(tai); for(i=0;i<a;i++){ if(tai[i] == '='){ co++; } } b=co; char *nameset[b]; char *valueset[b]; *nameset[0]=*strtok( tai,"&=" ); i=1; co=0; while ( tp != NULL ) { if(0==i%2){ co=i/2; *nameset[co] = *strtok( NULL,"&=" ); } else{ co=i/2; *valueset[co] = *strtok( NULL,"&=" );} i++; } for(i=0;i<b;i++){ printf("%s : %s\n",nameset[i],valueset[i] ) } } ---ソースここまで--- どうしたらちゃんと変数に格納されますか?

  • 動かないです

    おかしなところが有ったらアドバイス・修正等お願いします。 うしろ3行を表示させたいです。 0~2行の場合はその分だけ表示させたいです。 # include <stdio.h> # include <stdlib.h> # include <string.h> char *getline(void) { char *buf = NULL; int size = 0; int oldsize; do { oldsize = size; size = size * 2 + 80; buf = realloc(buf, size + 1); if(!buf) { fprintf(stderr, "memory allocation failed\n"); exit(1); } if(!fgets(buf + oldsize, size + 1 - oldsize, stdin)) if(oldsize) break; else { free(buf); return NULL; } }while(strlen(buf + oldsize) == size - oldsize); return buf; } void scan(char **lines, int n_lines) { char *p; int i; for(i = 0; i < n_lines; i++) lines[i] = NULL; while(p = getline()) { free(lines[0]); for(i = 0; i < n_lines - 1; i++) lines[i] = lines[i+1]; lines[n_lines - 1] = p; } } void print(char **lines, int n_lines) { int i; for(i = 0; i < n_lines; i++) if(lines[i]) fputs(lines[i], stdout); } int main(void) { char *lines[3]; int i; scan(lines, 3); print(lines, 3); for(i = 0; i < 3; i++) free(lines[i]); return 0; }

  • C言語計算プログラム

    Cの計算プログラム 下のプログラムを (1)上位桁の不要な0を表示しない (2)3つの数を計算できるようにする (3)0が入力されるまでは入力を受け付けて加算を繰り返す プログラムに改造する方法を教えてください。 #include <stdio.h> #define MAXDIGIT 70 void reset(char*,int); void input(char*,int); void add(char*,char*,char*,int); void add_digit(char ,char ,char ,char* ,char* ); void display(char* ,char* ,char* ,int ); void lineprint(char ,char* ,int ); void linedraw(char ,int ); int main(void) { char a[MAXDIGIT],b[MAXDIGIT],c[MAXDIGIT]; reset(a,MAXDIGIT); reset(b,MAXDIGIT); reset(c,MAXDIGIT); input(a,MAXDIGIT); input(b,MAXDIGIT); add(a,b,c,MAXDIGIT); display(a,b,c,MAXDIGIT); return 0;} void reset(char* buf,int maxdigit) { int i; for(i=0;i<maxdigit;i++) buf[i]=0; return;} void input(char* buf,int maxdigit) { char str[MAXDIGIT]; int i,j; printf("input data:"); scanf("%s",str); i=0; while(str[i]!='\0') i++; j=0; while(i>0){ buf[j]=str[i-1]-'0'; j++; i--; } return;} void add(char* a,char* b,char* c,int maxdigit) { int i; char carry_in,carry_out; i=0; carry_in=0; while(i<maxdigit) { add_digit(a[i],b[i],carry_in,&c[i],&carry_out); carry_in=carry_out; i++;} return;} void add_digit(char a,char b,char carry_in,char* c,char* carry_out) { *c=(a+b+carry_in)%10; *carry_out=(a+b+carry_in)/10; return;} void display(char* a,char* b,char* c,int maxdigit) { lineprint(' ',a,maxdigit); lineprint('+',b,maxdigit); linedraw('-',maxdigit+1); lineprint(' ',c,maxdigit); return;} void lineprint(char c,char* line,int maxdigit) { int i,maxdigitlimit; maxdigitlimit=maxdigit-1; printf("%c",c); for(i=maxdigitlimit;i>=0;i--){ printf("%1d",line[i]); } printf("\n"); return;} void linedraw(char c,int length) { int i; for(i=0;i<length;i++) printf("%c",c); printf("\n"); return;}

  • 二進検索木

    下記のプラグラムで二進検索木を作りたいのですが、うまくいきません(2つまでしか保存ができない)。 たぶん、ポインタがおかしいと思うのですが・・・。お願いします。 入力 年齢 1 名前 a メアド a@ 年齢 2 名前 b メアド b@ 年齢 3 名前 c メアド c@ 年齢 -1 出力 b  ×  c   ×   × 歳 2 名前 b メアド b@ 歳 3 名前 c メアド c@ #include<stdio.h> #include<stdlib.h> struct node{ char *name; char *email; int age; struct node *left; struct node *right; }; void getline(char *s,int n){ int c; while(--n>0&&((c=getchar())!=EOF && c!='\n')) *s++=c; *s='\0'; } char* dupstr(char* strg){ char* newstr; newstr = (char*)malloc(sizeof(char)*strlen(strg)); strcpy(newstr,strg); return newstr; } struct node *new(int n,char *na,char *em){ struct node *p; p=malloc(sizeof(struct node)); p->age=n; p->name=na; p->email=em; p->left=NULL; p->right=NULL; return p; } void print(struct node *p){ if(p==NULL)return; else{ print(p->left); printf("\n歳:%d ", p->age); printf("\n名前:%s ", p->name); printf("\nメアド:%s ", p->email); print(p->right); } } void print_tree(struct node *p,int level){ int i; for(i=0;i<level;i++)printf(" "); if(p==NULL)printf("×\n"); else{ printf("%s\n",p->name); print_tree(p->left,level+1); print_tree(p->right,level+1); } } void *insert(struct node *p,int n,char *na,char *em){ int c; c=strcmp(p->name,na); if(c==0); else if(c>0){ if(p->left==NULL) {p->left=new(n,na,em); return p;} else insert(p->left,n,na,em); } else{ if(p->right==NULL){ p->right=new(n,na,em); return p;} else insert(p->right,n,na,em); } } main() { int age,g; char buf[80],a[80],b[80],*email,*name; struct node *root=NULL; g=1; printf("\n歳を入力:"); getline(buf,sizeof(buf)); printf("\n名前入力:"); getline(a,sizeof(a)); name=dupstr(a); age=atoi(dupstr(buf)); printf("\nメアド入力:"); getline(b,sizeof(b)); email=dupstr(b); root=new(age,name,email); while(g==1){ printf("\n歳を入力:"); getline(buf,sizeof(buf)); age=atoi(dupstr(buf)); if(age==-1) break; printf("\n名前入力:"); getline(a,sizeof(a)); name=dupstr(a); printf("\nメアド入力:"); getline(b,sizeof(b)); email=dupstr(b); root=insert(root,age,name,email); } print_tree(root,0); print(root); }

  • C言語 配列挿入

    失礼します。カンマ区切りのC言語を配列に挿入したいのですが、エラーが出てしまいます。 初心者的な質問で申し訳ございませんが、よろしくお願いします。 途中までですが、コードを掲載させていただきます。 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include<string.h> #define piyo 11 #define hoge 2900 int main(void) { FILE *fp; char test[piyo][hoge]; char buf[hoge]; char *ary[hoge]; int i, k; test[piyo][hoge] = NULL; if ((fp = fopen("testfile.csv", "r")) == NULL) { printf("\aファイルをオープンできません\n"); }else{ while (fgets(buf, hoge, fp) != NULL) { for (k = 0; k < hoge; k++) { ary[k] = strtok(buf, ","); } } fclose(fp); return(0); } エラーメッセージ 警告 C4047 '=': 間接参照のレベルが 'char' と 'void *' で異なっています。 C1075 左側の 中かっこ '{' に対応するものがファイルの最後まで検出されませんでした。

  • C言語 家系図

    問題 構造体personを以下のように仮定する。 struct person { int age; char name[20]; struct person *father; struct person *mother; }; この構造体の表す人の名前、年齢、その人の父親の名前、およびその人の母親の名前を出力する関数 void print_person(struct person *p) を作成せよ。出力の形式は name: 本人の名前 age: 本人の年齢 father: 父親の名前 mother: 母親の名前 となるようにすること。 また、ポインタ father や mother の値が NULL のときには、名前のかわりに unknown と出力するようにせよ。 以上が問題なのですが自分でプログラムを作ってみたところ実行したら、エラーになって矯正終了されてしまいました。 以下が私の作ったプログラムです。 #include <stdio.h> struct person { int age; char name[20]; struct person *father; struct person *mother; }; void set_name(struct person *p, char name[]) { int i; i = 0; while (name[i] != 0) { p->name[i] = name[i]; i++; } p->name[i] = 0; } void print_person(struct person *p) { printf("name:%s", p->name); printf("age:%s\n",p->age); if(p->father != NULL){ printf("father:%s\n",p->father); } else{ printf("unknown"); } if(p->mother != NULL){ printf("mother:%s\n",p->mother); } else{ printf("unknown"); } } int main(void) { struct person me, dad, mom; set_name(&me, "Michael"); me.age = 16; me.father = &dad; me.mother = &mom; set_name(&dad, "David"); dad.age = 38; dad.father = NULL; dad.mother = NULL; set_name(&mom, "Susan"); mom.age = 36; mom.father = NULL; mom.mother = NULL; print_person(&me); print_person(&dad); print_person(&mom); return (0); } どこが違うのか教えていただけないでしょうか?

  • C言語に関する質問

    初めて質問させて頂きます。C言語初心者です。 実は講義で「ファイル中の英文を単語に分けてその出現頻度をカウントするコードを木構造を用いて出力せよ」という課題が出ました。 そこで、参考にするコードを検索しましたところ、以下のURLにあるベストアンサーのコードが近いと感じました。 http://okwave.jp/qa/q4155655.html コードの内容は以下の通りになります。 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> typedef struct node Node; struct node{ char *word; int count; Node *left,*right; }; Node *root=NULL; void compose(FILE *fp); void inorder(Node *p); void strlower(char *s); int main(int argc, char *argv[]) { FILE *fp; Node *new; fp=fopen(argv[1],"r"); if(fp==NULL){puts("ファイルを開けません");return(-1);} compose(fp); inorder(root); return (0); } void strlower(char *s){ while(*s!=NULL){*s=tolower(*s);s++;} } void compose(FILE*fp){ Node **p,*new; char buf[256]; while(1){ fscanf(fp,"%[^a-zA-Z0-9]",buf); if(fscanf(fp,"%[a-zA-Z0-9]",buf)==EOF)break; strlower(buf); if(root==NULL){ new=(Node *)malloc(sizeof(Node)); new->left=NULL; new->right=NULL; new->word=strdup(buf); new->count=1; root=new; }else{ *p=root; while(1){ if(strcmp(buf,(*p)->word)==0){ (*p)->count++;break; }else if(strcmp(buf,(*p)->word)<0){ if((*p)->left==NULL){ new=(Node *)malloc(sizeof(Node)); new->left=NULL;new->right=NULL;new->word=strdup(buf);new->count=1; (*p)->left=new; break; }else{ *p=(*p)->left; } }else{ if((*p)->right==NULL){ new=(Node *)malloc(sizeof(Node)); new->left=NULL; new->right=NULL; new->word=strdup(buf); new->count=1; (*p)->right=new; break; }else{ *p=(*p)->right; } } } } } } void inorder(Node*p){ if (p==NULL) return; inorder(p->left); printf("%s %d\n",p->word, p->count); inorder(p->right); } しかし、これをそのままコンパイル・実行すると、コンパイル時に以下の注意が出ます。 warning comparison between pointer and integer ('int' and 'char *') while(*s!=NULL){*s=tolower(*s);s++;} 上記の注意を無視してそのまま実行すると、segmatation faultが出てしまいますorz おそらく、sの型が*s=s[]なので、注意の中の「s++」の部分で誤作動を起こしている(s++を実行するにはsはint型でなければならない)と思うのですが、どうコード文を変えれば良いのかがよくわかりません。 どなたかお教え頂けると幸いです。どうぞよろしくお願いしますm(_ _)m

  • 多桁 計算プログラム

    下のプログラムを (1)上位桁の不要な0を表示しない (2)3つの数を計算できるようにする (3)0が入力されるまでは入力を受け付けて加算を繰り返す プログラムに改造する方法を教えてください。 #include <stdio.h> #define MAXDIGIT 70 void reset(char*,int); void input(char*,int); void add(char*,char*,char*,int); void add_digit(char ,char ,char ,char* ,char* ); void display(char* ,char* ,char* ,int ); void lineprint(char ,char* ,int ); void linedraw(char ,int ); int main(void) { char a[MAXDIGIT],b[MAXDIGIT],c[MAXDIGIT]; reset(a,MAXDIGIT); reset(b,MAXDIGIT); reset(c,MAXDIGIT); input(a,MAXDIGIT); input(b,MAXDIGIT); add(a,b,c,MAXDIGIT); display(a,b,c,MAXDIGIT); return 0;} void reset(char* buf,int maxdigit) { int i; for(i=0;i<maxdigit;i++) buf[i]=0; return;} void input(char* buf,int maxdigit) { char str[MAXDIGIT]; int i,j; printf("input data:"); scanf("%s",str); i=0; while(str[i]!='\0') i++; j=0; while(i>0){ buf[j]=str[i-1]-'0'; j++; i--; } return;} void add(char* a,char* b,char* c,int maxdigit) { int i; char carry_in,carry_out; i=0; carry_in=0; while(i<maxdigit) { add_digit(a[i],b[i],carry_in,&c[i],&carry_out); carry_in=carry_out; i++;} return;} void add_digit(char a,char b,char carry_in,char* c,char* carry_out) { *c=(a+b+carry_in)%10; *carry_out=(a+b+carry_in)/10; return;} void display(char* a,char* b,char* c,int maxdigit) { lineprint(' ',a,maxdigit); lineprint('+',b,maxdigit); linedraw('-',maxdigit+1); lineprint(' ',c,maxdigit); return;} void lineprint(char c,char* line,int maxdigit) { int i,maxdigitlimit; maxdigitlimit=maxdigit-1; printf("%c",c); for(i=maxdigitlimit;i>=0;i--){ printf("%1d",line[i]); } printf("\n"); return;} void linedraw(char c,int length) { int i; for(i=0;i<length;i++) printf("%c",c); printf("\n"); return;}

専門家に質問してみよう