もう、しばらくは結構です(^^;
普段使いなら、Perlで十分過ぎますので。。。
すっかり色々忘れてて、凹んだ。
初歩的なんだけど、malloc()の使い方も完璧忘れてました。
せっかくなので備忘録として。malloc()で双方向リストを操作するサンプル。
//**********************************************************実行するととにかく文字列(半角99文字まで)の文字列をひたすら入力する。
// メモリ操作のテスト
// 両方向リストの作成
//**********************************************************
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NAME_LENGTH 100
typedef struct NAMELIST {
struct NAMELIST *back;
int number;
unsigned char name[NAME_LENGTH];
struct NAMELIST *next;
}_NAMELIST;
struct NAMELIST *add(unsigned char *name, struct NAMELIST *name_last);
struct NAMELIST *getStart(struct NAMELIST *p);
struct NAMELIST *getLast(struct NAMELIST *p);
void print_list(struct NAMELIST *namelist);
void free_list(struct NAMELIST *p);
//=============================================================================
// メイン
//=============================================================================
int main(int argc, char *argv[]) {
int i = 0;
for(i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
unsigned char buf[NAME_LENGTH];
struct NAMELIST *p = NULL;
printf("input, added string.(end = EOF)\n");
while(scanf("%s", buf) != EOF) {
if(!strcmp(buf, "q")) {
break;
}
p = add(buf, p);
}
print_list(p);
free_list(p);
return 0;
}
//=============================================================================
// データの追加
// 戻り値=struct NAMELIST *追加したデータへのポインタ
//=============================================================================
struct NAMELIST *add(unsigned char *name, struct NAMELIST *name_last) {
struct NAMELIST *name_new;
if((name_new = (struct NAMELIST *)malloc(sizeof(struct NAMELIST))) == NULL) {
printf("memory allocation failed. = malloc() error\n");
exit(EXIT_FAILURE);
}
// 確保したメモリに入力値を保存する
strncpy(name_new->name, name, (size_t)NAME_LENGTH);
// 今回のポインタのbackを前回のポインタにつなぐ
name_new->back = name_last;
// 今回のポインタのnextをNULLに
name_new->next = NULL;
// 前回のポインタのnextを今作成したメモリにつなぐ(NULLの時を除く)
if(name_last != NULL) {
name_last->next = name_new;
};
return name_new;
}
//=============================================================================
// 最初のデータへのポインタを求める
// 戻り値=struct NAMELIST *最初のデータへのポインタ
//=============================================================================
struct NAMELIST *getStart(struct NAMELIST *p) {
struct NAME *q;
if(p == NULL) {
return (struct NAMELIST *)NULL;
}
while(p->back != NULL) {
p = p->back;
}
return p;
}
//=============================================================================
// 最後のデータへのポインタを求める
// 戻り値=struct NAMELIST *最後のデータへのポインタ
//=============================================================================
struct NAMELIST *getLast(struct NAMELIST *p) {
struct NAME *q;
while(p->next != NULL) {
p = p->next;
}
return p;
}
//=============================================================================
// データをすべて表示する
//=============================================================================
void print_list(struct NAMELIST *namelist) {
namelist = getStart(namelist);
while(namelist != NULL) {
printf("%s\n", namelist->name);
namelist = namelist->next;
}
}
//=============================================================================
// データ用として確保したメモリをすべて解放する
//=============================================================================
void free_list(struct NAMELIST *p) {
struct NAMELIST *q;
while (p != NULL) {
q = p->back;
free(p);
p = q;
}
}
データが入力される度にmalloc()でメモリを確保して、データを格納する。
qが入力されるとそれまで入力したデータを表示する・・・という単純なもの。
データの形はstruct NAMELISTで定義している。
最初はデータを示すポインタがNULLをさしている。
データを作ると、ポインタはデータの位置になる。
データの形式は
・次のデータを指し示すポインタ
・実際の格納されるデータ
・前のデータを指し示すポインタ
から成り立っていて、
新たにデータを作るとき、、、
・次のデータを指し示すポインタはNULLにする
・実際のデータを格納する
・前のデータを指し示すポインタは前の構造体を示す
というデータにする。
次のデータも前のデータも(データを見ることで)つながりが分かるので双方向リストと言うらしい。
malloc()を使う意味というか、、、メモリがある限り、動的にデータの保管場所を増やせるのがメリットになる。逆に解放忘れがあると、いわゆるメモリリークの元になるので注意が必要だが。
逆にmalloc()を使う必要が無い例としては、それほど巨大なメモリを確保する必要が無い場合、あらかじめ必要になるデータ量が決まっている場合・・・などはmalloc()を使うより、配列を使った方が安全。
とな。
完全に「復習」の備忘録。
こんな事(データの格納方法)を考えなくても、push()、pop()でリスト(スタック)操作ができたり、、hash変数が使えたり、SORT()も関数一発だったり・・・と、perlの便利さが身に染みてます。。。
コメント