' P '

whatever I will forget

C 動的な文字列リストの作り方メモ

おことわり

コンパイルしてません。 ただの自メモなので、関数などを省略している時点で察してください

やりたいこと&仕様

  1. char型の文字列リストを動的に保存したい
  2. 文字列の格納MAX数、格納される変数のlengthは固定されている
  3. 何個の文字列が格納されるかは不明
  4. 関数に空の箱をパラメーターとして渡して関数内でリストを作成する
  5. 関数呼び出し後(元で)、リスト変数を使用したい
  6. mallocやトリプルポインターは使いたくない(読みやすさを重視したい)

上記のようなことがやりたかったのですが、ググっても基本char型二次元リストは元々文字列が固定されているような例ばかりだったため、メモしておきます

実装

構造体の配列を使用しました。

//関数プロトタイプ
int func_make_list(data_list**, int*);
int func_use_list(data_list); //関数内の処理は省略
int some_func(char**);        //関数内の処理は省略

//globalに定義しました
typedef struct tmp{
  char data[10]; //変数のlengthは10で固定
}data_list;

... //int main()は省略

int main_func() {
  //配列数は100個で固定
  data_list data_list[100];    
  //data_listの構造体配列のアドレスを格納                
  data_list* data_list_address = NULL;
  //構造体配列変数の初期化
  memset(data_list, 0x00, sizeof(data_list));
  int data_cnt = 0;

  //関数には構造体変数のアドレスを渡す
  func_make_list(&data_list_address, &data_cnt);
  //関数内で作成した実体をdata_listにコピー
  memcpy(data_list, data_list_address, sizeof(data_list));

  for (int i = 0; i < data_cnt; i++) {
    //listの値をひとつずつ使用する(関数の内容は省略)
    func_use_list(data_list[i]);
  }
}

int func_make_list(char** data, int* data_cnt) {
  //関数内でdata_list型の構造体を宣言
  data_list tmp_data_list[100];
  int return_code = 0;
  char value[10];
   
  while(return_code == 0){
    //何かしら値を取得する関数があると仮定します
    //関数内で返却される値は必ずchar型10バイトと仮定します
    return_code = some_func(&value);
    if (return_code != 0) {
      break;
    }
    //関数内で取得した値を1つずつ配列にセット
    memcpy(tmp_data_list[i].data, value, 10);
    i++;
  }
  //関数引数のシングルポインタ(アドレス)に構造体をセット
  *data = tmp_data_list;
  //セットしたデータ数をセット
  *data_cnt = i;
}

追記。作成した構造体配列を関数に渡す際。

上記の例は実体で渡す際の例。もしポインタで渡したい場合は単純に

  for (int i = 0; i < data_cnt; i++) {
    //listの値をひとつずつ使用する(関数の内容は省略)
    func_use_list(data_list[i]);
  }

// 省略

void func_use_list (datalist* data_list) {
  char data[10];
  memcpy(data, data_list->data, sizeof(data));
// 省略
  func_use_list2(data_list);
}

void func_use_list2(datalist* data_list){
// 省略
}

としましょう。 さらに呼び出し後関数で使用したい場合で、関数元で使用する必要が無い場合は同じように渡すだけです。
ちょっと混乱してしまいましたが、呼び出し元関数ですでにindexを指定しているので、
呼び出し後の関数で使用されている変数はすでにindexが指定されているため、普通の構造体変数と同じように扱えます。
data_list[data_cnt]みたいにして次関数に渡してしまうと、構造体の二次元配列を意味することになるので注意。