• ベストアンサー

C言語解読

#include <stdio.h> #include <stdlib.h> #include <string.h> #define dBufferSize (32768) #define dPrintFmt "#d: %s\n" typedef struct _NODE NODE; struct _NODE { char *line; NODE *next; }; int RemoveReturnCode(char *string); NODE *MakeNode(char *string); int FreeNodeList(NODE *node); void FreeNode(NODE *node); int PrintNoceList(NODE *node); NODE *ReverseNodeList(NODE **head); int main(void){ char buffer[dBufferSize]; NODE *head = NULL; while (fgets(buffer, dBufferSize, stdin) != NULL){ NODE *pivot; RemoveReturnCode(buffer); pivot = MakeNode(buffer); if (pivot == NULL) return FreeNodeList(head); pivot->next = head; head =pivot; } PrintNodeList(head); ReverseNodelist(&head); PrintNodeList(head); FreeNodeList(head); return 0; } int RemoveReturnCode(char *str){ char *p; if (str == NULL) return -1; for (p = str; *p != '\n' && *p != '\r' && *p != '\0'; p++) ; *p = '\0'; return p - str; } NODE *MakeNode(char *str){ NODE *node; if(str == NULL)return NULL; node = (NODE *)calloc(1,sizeof(NODE)); if(node != NULL){ char *p = (char *)calloc(strlen(str)+1, sizeof(char)); if (p != NULL){ node->line = strcpy(p, str); node->next = NULL; } else{ free(node); node = NULL; } } return node; } int FreeNodeList(NODE *node){ int ct = 0; while (node != NULL){ NODE *next = node->next; FreeNode(node); ct++; node = next; } return ct; } void FreeNode(NODE *node){ free(node->line); free(node); } int PrintNodeList(NODE *node){ int ct; for (ct = 0; node != NULL; node = node->next, ct++) printf(dPrintFmt, ct+1, node->line); return ct; } NODE *ReverseNodeList(NODE **head){ NODE *reverse = NULL; NODE *node = *head; while (node != NULL){ NODE *next = node->next; node->next = reverse; reverse = node; node = next; } return *head = reverse; } このプログラムは単方向リストを利用して複数行のデータを格納していくものであるという ものらしいのですが、そのようなヒントがあっても、まったく解読できません、 手も足も出ない状態です。 できれば、初心者に近い私にもわかるように、関数ごとの解説をおねがいします!! エラーがでるかもしれないのですが・・・大体の意味にはかわりないと思いますので、宜しくお願いします!!

  • 32i
  • お礼率33% (3/9)

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

  • ベストアンサー
noname#119918
noname#119918
回答No.2

コメントで解説を加えておきました。 基本的なアルゴリズムですので、構造は難しくないと思います。 一度ご自分でリストを作成するプログラムを記述することをお勧めします。 #include <stdio.h> #include <stdlib.h> #include <string.h> #define dBufferSize (32768) // 1行分の文字列を保持するためのバッファのサイズ #define dPrintFmt "%d: %s\n" // 文字列を表示する際の書式 // 連結リストを実現するための構造体 // NODE構造体をつなげてリストを作成する typedef struct _NODE NODE; struct _NODE { char *line; // 文字列へのポインタ NODE *next; // 次のNODEへのポインタ }; int RemoveReturnCode(char *string); NODE *MakeNode(char *string); int FreeNodeList(NODE *node); void FreeNode(NODE *node); int PrintNodeList(NODE *node); NODE *ReverseNodeList(NODE **head); int main(void){ char buffer[dBufferSize]; // 1行分の文字列を保持するバッファ NODE *head = NULL; // 標準入力から1行毎に文字列を読み取り、連結リストに格納 while (fgets(buffer, dBufferSize, stdin) != NULL){ NODE *pivot; RemoveReturnCode(buffer); // 文字列末尾の改行コードを削除 pivot = MakeNode(buffer); // 新規NODE作成 if (pivot == NULL) return FreeNodeList(head); // NODE作成に失敗した場合は、リストを削除して終了 // 作成したNODEをリスト先頭に挿入 pivot->next = head; head = pivot; } PrintNodeList(head); // リストを表示 ReverseNodeList(&head); // リストを逆転 PrintNodeList(head); // リストを表示 FreeNodeList(head); // リストを削除 return 0; } /* 文字列末尾の改行コードを削除 @param str 文字列 @return 文字列長 */ int RemoveReturnCode(char *str){ char *p; if (str == NULL) return -1; for (p = str; *p != '\n' && *p != '\r' && *p != '\0'; p++) ; *p = '\0'; return p - str; } /* 新規に文字列を保持するNODE作成 @param str 文字列 @return 作成したNODE(作成失敗の場合NULL) */ NODE *MakeNode(char *str){ NODE *node = NULL; if(str == NULL)return NULL; node = (NODE *)calloc(1,sizeof(NODE)); if(node != NULL) { // node領域確保成功 char *p = (char *)calloc(strlen(str)+1, sizeof(char)); // 文字列を保持する領域を確保 if (p != NULL) { // p領域確保成功 node->line = strcpy(p, str); // 文字列をコピー node->next = NULL; } else { // p領域確保失敗 free(node); node = NULL; } } else { // node領域確保失敗 node = NULL; } return node; } /* 連結リストを削除 @param node 先頭のNODE @return 削除したNODEの数 */ int FreeNodeList(NODE *node){ int ct = 0; while (node != NULL){ NODE *next = node->next; FreeNode(node); ct++; node = next; } return ct; } /* 単一のNODEを削除 @param node 削除するNODE */ void FreeNode(NODE *node){ free(node->line); free(node); } /* 連結リストが保持する文字列を1行毎に表示 @param node 先頭のNODE @return 表示した行数 */ int PrintNodeList(NODE *node){ int ct; for (ct = 0; node != NULL; node = node->next, ct++) printf(dPrintFmt, ct+1, node->line); return ct; } /* 連結リストを逆転 @param head 先頭のNODEへのダブルポインタ */ NODE *ReverseNodeList(NODE **head){ NODE *reverse = NULL; NODE *node = *head; while (node != NULL){ NODE *next = node->next; node->next = reverse; reverse = node; node = next; } return *head = reverse; }

32i
質問者

お礼

お礼遅くなってごめんなさい。 C言語にCASL、とプログラミングに翻弄された 日々がいったん落ち着くまで時間がかかりました。 そういってる間に試験が近づいています。。 また、回答者様にはくだらない問題かもしれませんが、 気が向けば、手助けをお願いいたします。 ありがとうございました。

その他の回答 (1)

回答No.1

   向こうの人に失礼なことはやめましょう。  初心者なら、解るようになるまで勉強しましょう。 いきなり二階へ飛び上がるのは無理です。 ちゃんと階段を一段づつ上がりましょう。    

関連するQ&A

  • C言語 リスト

    (1) /* list.c */ #include <stdio.h> #include <stdlib.h> struct node { int num; struct node *next; }; main() { struct node *head, *p; int x; head = NULL; while(scanf("%d",&x) != EOF) { p = (struct node *)malloc(sizeof(struct node)); p->num = x; p->next = head; head = p; } // リストの要素のnumの値を先頭から順に表示する p=head; while(p!=NULL) { printf("%d\n" ,p->num); p = p->next; } } (2) struct node *q; q = head; while(q->next != NULL) q = q->next; (1)を(2)を使い新しいノードをリストの最後に追加するようにしたいのですが どう書いたら良いのか教えていただきたいです

  • C言語 線形探索

    #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXBUFFERSIZE 256 struct LinkedListNode{ int data; struct LinkedListNode *next; }; struct LinkedList{ int node_num; struct LinkedListNode *head; }; LinkedList *LinkedListMake(char *filename) { FILE *fp; LinkedList *list; char buffer[MAXBUFFERSIZE]; /* ファイル有無のチェック */ if ((fp = fopen(filename, "r")) == NULL) { fprintf(stderr, "No Such File : %s\n", filename); exit (1); } list = LinkedListAlloc(); if (list == NULL) { /* 領域確保失敗 */ exit (0); /* 終了 */ } while (fgets(buffer, MAXBUFFERSIZE, fp)) { /* ファイル終端に到達するまでループ */ buffer[strlen(buffer) - 1] = '\0'; /* 改行文字を削除 */ LinkedListDataAdd(list, atoi(buffer)); } fclose(fp); return (list); } LinkedList *LinkedListAlloc(void) { LinkedList *list; list = (LinkedList *)malloc(sizeof(LinkedList)); if (list == NULL) { /* 領域確保失敗 */ return (NULL); } list->node_num = 0; list->head = NULL; return (list); } LinkedListNode *LinkedListDataAdd(LinkedList *list, int x) { LinkedListNode *ptr; /* 注目するノードへのポインタ */ LinkedListNode *prev; LinkedListNode *new_node; ptr = list->head; prev = NULL; while (ptr) { /* 終端ノードに到達するまでループ */ if (ptr->data < x) { prev = ptr; /* 直前ノードの更新 */ ptr = ptr->next; /* 注目ノードの更新 */ } else if (ptr->data == x) { /* x は登録済み */ return (NULL); } else { /* x を注目ノードの直前に追加 */ new_node = LinkedListNodeAlloc(); if (new_node == NULL) { /* 領域確保失敗 */ exit (0); /* 終了 */ } new_node->data = x; new_node->next = ptr; /* ポインタの付け替え(注目ノードの直前) */ if (prev != NULL) { /* 連結リストの先頭以降に追加 */ prev->next = new_node; /* ポインタの付け替え */ } else { /* 連結リストの先頭に追加 */ list->head = new_node; } list->node_num++; /* ノード総数の更新 */ return (new_node); } } /* 終端ノードに到達 */ /* x を終端に追加 */ new_node = LinkedListNodeAlloc(); if (new_node == NULL) { /* 領域確保失敗 */ exit (0); /* 終了 */ } new_node->data = x; new_node->next = NULL; /* new_node は新たな終端ノード */ if (prev != NULL) { /* list は少なくともひとつのノードを有している */ prev->next = new_node; /* 更新前の終端ノードの直後が new_node となる */ } else { /* list は空(ノードがひとつも含まれない) */ list->head = new_node; } list->node_num++; /* ノード総数の更新 */ return (new_node); } LinkedList *LinkedListSearch(LinkedList *list, int x)←ここがわかりません★ { for(i = 0; i < node_num)      ??? int main(int argc, char *argv[]) { int a, i, x; printf("xの値を入力"); scanf("%d", &x); LinkedListMake(argv[1]); LinkedListSearch(list, x); 連結リストに格納されたint型データから目的の値を線形探索するプログラムをつくってます。 連結リスト作成関数まではできたので、あと連結リストにおいて目的の値を線形探索する関数LinkedListSearchをつくればだいたい完成だと思うのですが、関数LinkedListSearchの作り方がわかりません。 引数で連結リストのポインタと目的値をとって、目的値が存在すればそのノードのポインタ、存在しない場合はNULLを返すようにするつもりです。 わかる方、是非とも教えてください! お願いいたします。

  • C言語でセグメンテーションエラー

    環境はUbuntu Feisty Fawn gcc 4.1.2 #include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX 32 #define DEBUG struct node{ char *moji; struct node *left,*right; }; typedef struct node NODE; void error(char *msg){ fflush(stdout); fprintf(stderr, "%s\n", msg); exit(1); } NODE *createNode(char *x){ NODE *new; new = malloc(sizeof(NODE)); if(new == NULL){ error("メモリがありません。\n"); } new->moji = x; new->left = NULL; new->right = NULL; return new; } NODE *insertNode(NODE *p, char *x){ if(p == NULL){ p = createNode(x); }else if(strcmp(p->moji, x) == 0){ return NULL; }else if(strcmp(p->moji, x) > 0){ p->left = insertNode(p->left, x); }else{ p->right = insertNode(p->right, x); } return p; } void printTree(NODE *p){ if(p == NULL) return; printTree(p->left); printf("%s\n",p->moji); printTree(p->right); } int main(int argc, char *argv[]){ FILE *fp; char *buf = malloc(sizeof(char) * MAX); char *ans = malloc(sizeof(char) * MAX); NODE *p = malloc(sizeof(NODE)); if( argc > 2 ){ printf("ファイルの指定は一つだけです。\n"); return -1; }else if(argc == 1){ printf("ファイルを指定してください。\n"); return -1; } fp = fopen( argv[1] , "r" ); if( fp == NULL ){ printf("ファイル読み込みに失敗しました。\n"); return -1; } while(fscanf(fp,"%s",buf) == 1){ ans = strtok(buf," -,."); p = insertNode(p, ans); while(ans != NULL){ ans = strtok(NULL," -,."); if(ans != NULL){ p = insertNode(p, ans); } } } printTree(p); fclose(fp); return 0; } このファイルを読み込んで記憶させたいんです。 file.txt ここから下がファイルの中身 The Java programming language is a general-purpose, concurrent, class-based, object-oriented language. It is designed to be simple enough that many programmers can achieve fluency in the language. どこがいけないとおもいますか?

  • C言語 二分木探索

    今、int型の二分木にデータを追加する関数(引数は二分木へのポインタと追加する値、追加されたノードへのポインタを返す)をつくろうとしてます。 以前リストにデータを追加する関数をつくったのでそれを変更してつくろうとしているのですが途中までいってつまってしまいました。 つくりかたを教えてください。 よろしくお願いします! struct BinaryTreeNode{ int data; struct BinaryTreeNode *l_next; struct BinaryTreeNode *r_next; }; struct BinaryTree{ int node_num; struct BinaryTreeNode *root; }; BinaryTreeNode *BinaryTreeNodeAlloc(void) { BinaryTreeNode *node; node = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode)); if (node == NULL) { return (NULL); } node->l_next = NULL; node->r_next = NULL; return (node); } BinaryTreeNode *BinaryTreeDataAdd(BinaryTree *list, int x) { BinaryTreeNode *ptr; BinaryTreeNode *prev; BinaryTreeNode *new_node; ptr = list->root; prev = NULL; while (ptr) {       ←?? if (ptr->data < x) { prev = ptr; ptr = ptr->next; } else if (ptr->data == x) { return (NULL); } else { new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0);                ←?? } new_node->data = x; new_node->next = ptr; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); } } new_node = BinaryTreeNodeAlloc(); if (new_node == NULL) { exit (0); } new_node->data = x; new_node->r_next = NULL; new_node->l_next = NULL; if (prev != NULL) { prev->next = new_node; } else { list->head = new_node; } list->node_num++; return (new_node); }

  • C言語の、ポインターの問題を教えて下さい

    C言語の、ポインターを使って大文字と小文字を入れ替えるプログラムを教えて下さい。 作ったのですが、うまくいかず困っています。 分かる方、訂正してください。 よろしくお願いいたします。 #include<stdio.h> void reverse(char *str) { int i; for(i=0;str[i]!='\0';i++) { if(str[i]>=0x61) {str[i]-0x20;} if(0x40<str[i]<0x5B) {str[i]+0x20;} } return(str); } int main(void) { int num; char *str="AddsssEEEEwwwJojoHoih"; printf("Before reverse %s \n",str) str=reverse(str); printf("After reverse %s \n",str); return 0; }

  • 【C言語】構造体内の領域解放(free)の仕方

    教えてGoo運営側に内容チェックされているため再度内容を変更し質問させていただきます。 http://okwave.jp/qa/q8080757.html (ダンプを書いたのがまずかったかもしれないので、ここでは削除します。) <プログラムで実行したいこと> ・簡単なリストを作成 ・リストを構成する構造体のメンバはchar*などのメンバがあり、  特に、char*にstrdupにて文字列をコピーする。(正確には文字列のポインタをコピーする。) ・作ったリストをプリントする。 ・領域を確保する。 下記のソースで動くと思ったのですが、領域のfreeでうまくいきません。 どうもない領域をfreeしているようなのです。それがなぜかわかりません。 *** glibc detected *** ./a.out: free(): invalid pointer: 0x00000000020eb030 *** どうしたら、解決するのか、どこが悪いのかご指摘いただけないでしょうか。 以下、私が書いたソースになります。 #include<stdio.h> #include<stdlib.h> #include<string.h> struct word { struct word *next; char *st; int *line_no; int line_cnt; }; struct word *head; void Add_List(char *buf,int no){ struct word* node = malloc(sizeof(struct word*)); struct word* crnt; /*nodeの準備*/ node->next = NULL; //node->st = strdup(buf); node->st = malloc(sizeof(char)*10); strcpy(node->st,buf); node->line_no = malloc(sizeof(int*)); node->line_no[0] = 1; node->line_cnt= 1; if(head == NULL) { head = node; } else { crnt = head; while( crnt->next != NULL) { crnt = crnt->next; } crnt->next = node; } } void printlist(){ struct word *crnt = head; while( crnt != NULL ) { printf("%s\n",crnt->st); crnt = crnt->next; } } int main(){ head = NULL; char buf1[] = {'A','B','C','D','E','\0'}; char buf2[] = {'F','G','H','I','J','\0'}; char buf3[] = {'K','L','M','N','O','\0'}; Add_List(buf1,1); Add_List(buf2,1); Add_List(buf3,1); printlist(); /*この部分がうまくいかない*/ printf("%s\n",head->st); printf("%x \n",head->st); free(head->st); /*********************/ }

  • 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

  • C言語 ポインタと配列

    #include <stdio.h> /* scanf("%c", &search); ではなく scanf(" %c", &search); であることに注意する */ char *str_chr(const char *str, char c) { char *find; find = NULL; do { if(*str == c) { find = (char*)str; break; } } while(*str++); return(find); } int main(void) { char str[100] = {0}; char search; char *find; printf("文字列を入力してください:"); scanf("%s", str); printf("検索する文字を入力してください:"); scanf(" %c", &search); find = str_chr(str, search); if(find == NULL) { puts("検索した文字は見つかりませんでした。"); } else { printf("検索した文字 %c は\"%p\"にあります。\n", *find , find); } return(0); } このコードのfind = (char*)str;の (char*)str;の部分がどうなっているのかわかりません。 あとこのfindというのは&find[0]という解釈でいいでしょうか? 教えてくださいm(_ _ )m

  • C言語 複数ファイル操作について

    Cプログラミング初心者です。 論文などの何行も文章があるようなテキストファイル(ここでは1.txtとします)と、他に予め単語をいくつか登録しているテキストファイル(2.txt)を開き、1.txtを最初の行から一行ごとに読み込み、2.txtの中にある単語が1つでもその一行の文章中に含まれていたらその一行の文章を出力し、また次の行においても2.txtの中にある単語のいずれかが含まれているかどうかを調べて含まれている場合は出力…含まれていない場合は出力せずに次の行へ…といったようにこれを1.txt内の最後の行まで繰り返し行うプログラムを作りたいのですが、自分が作ったプログラムでは含む・含まない関係なく1.txt内の文章全てが出力されてしまいます。おそらく最初のwhile文あたりがおかしいのだろうという予想はつくのですがどのように直せばよいのかわからず悩んでいます。どなたか教えていただければ嬉しいです(;_:) #include <stdio.h> #include <stdlib.h> #include <string.h> #define N 1056 void delkaigyo(char *s1,char *s2){ char *p = s1; p=strstr(s1,s2); if(p!=NULL){ strcpy(p,p+strlen(s2)); delkaigyo(p+1,s2); } } int main(void){ FILE *fp; char *filename = "2.txt"; char str1[N]; char str2[N]; char kaigyo[] = "\n"; int i; int a=0; char fname[64]; printf("file:"); scanf("%s", fname);   ←ここで1.txtを入力するとします fp = fopen(fname, "r"); while(fgets(str1, N, fp) != NULL){ delkaigyo(str1, kaigyo); memset(str1, 0, N); fread(str1, 1, N-1, fp); if((fp = fopen(filename, "r")) == NULL){ fprintf(stderr, "%serror.\n", filename); exit(EXIT_FAILURE); } while(fgets(str2, N, fp) != NULL){ delkaigyo(str2,kaigyo); if(strstr(str1,str2)!=NULL){ a = 1; printf("%s\n", str1); break; } } if(a==0){ return 0; } fclose(fp); } return EXIT_SUCCESS; }

  • C言語 初心者です。

    今、英単語帳を作っているのですが、以下のソースではできません。 作ろうとしているプログラムは、a bを登録した場合、次がaabと来たら、 a aab bといったようにしたいのですが、できません。教えてください。 #include <stdio.h> #include <string.h> #define NUMBER 50 /*--- 単語帳の構造体*/ typedef struct { char *word; } words; /*--- 文字列strから文字列wordを検索する ---*/ char *str_chr(const char *str, int w) { for ( ; *str; *str++){ if (*str == w){ return ((char *)str); } } return (NULL); /*検索したが該当しないときはNULLを返す*/ } /*--- 単純交換ソート ---*/ void swap(int *x, int *y) { int temp = *x; *x = *y; *y = temp; } /*--- 配列dataの先頭n個の要素を昇順にソート ---*/ void sort(words data[], int n) { int k = n - 1; while (k >= 0){ int i, j; for (i = 1, j = -1; i <= k; i++) if (data[i - 1].word > data[i].word){ j = i - 1; swap(&data[i], &data[j]); } k = j; } } int main(void) { words word[NUMBER][20] = {{0},{0}}; char str[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; char w[128], *p; int count = 0; do{ printf("単語を入力してください。:"); /*単語を入力する*/ scanf("%s", w); p = str_chr(str, w); }while(p == NULL); count++; if(count >= NUMBER){ /*登録件数を調べる*/ printf("件数いっぱいです。\n"); } return (0); sort(word, NUMBER); return (0); }