こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

多元配列について(ANSI C)

動的多元配列で、
Voidポインタに、多種の型がぶら下がった多元配列を作り、
読み書きをしたいのですがどのようにしたらよろしいでしょうか。

具体的には、
x[0][1]は、intで「2」が入っている
x[0][4]は、intで「9」が入っている
x[1][2]は、charでしかも文字列の配列で「goo」が入っている
x[1][5]は、charでしかも文字列の配列で「教えて」が入っている
x[0]は、int型の配列。X[1]は、文字列型の配列。
というようなものです。

一応ソースは作ってみたのですが、int型では問題なくいくのですが、
文字列は、コンパイルはできますが、実行すると予期せぬことが起きます。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main (void) {
     void **topPointa;
     int * iDataInput;
     int * iDataOutput ;

     char * chDataInput;
     char * chDataInput2;

     char * chDataOutput1 ;

     // ポインタアドレス用のメモリ確保
     topPointa = (void *) calloc (10 , sizeof(void *));
     if(topPointa == NULL) {
          printf("メモリが確保できません\n");
          exit(-1);
     }

     //int配列のメモリ確保
     iDataInput = (int * ) calloc (10 , sizeof(int));
     if(iDataInput == NULL) {
          printf("メモリが確保できません\n");
          exit(-1);
     }

     iDataInput[0] = 3 ;
     iDataInput[1] = 4 ;
     topPointa[0] = (void * ) &iDataInput;

     //int配列の取り出し
     iDataOutput = *(int *) topPointa[0];
     printf( "int: %d\n", iDataOutput[0] );
     printf( "int: %d\n", iDataOutput[1] );

     //char配列 のメモリ確保
     chDataInput = (char * ) calloc (10 , sizeof(char *));
     if(chDataInput == NULL) {
          printf("メモリが確保できません\n");
          exit(-1);
     }
     chDataInput2 = (char * ) calloc (10 , sizeof(char));
     if(chDataInput2 == NULL) {
          printf("メモリが確保できません\n");
          exit(-1);
      }

     strcpy(chDataInput2 , "hoe");
     chDataInput[0] = &chDataInput2;

     topPointa[1] = (void * ) &chDataInput;

     //char配列の取り出し
     chDataOutput1 = *(char *) topPointa[1];

     printf( "char: %S\n", chDataOutput1[0] );

     free(iDataInput);
     free(chDataInput);
     free(chDataInput2);

     return 0;
}

言語は、C言語ANCI Cでお願いします。

以上。よろしくお願いします。

投稿日時 - 2008-05-29 14:46:34

QNo.4059697

すぐに回答ほしいです

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

★アドバイス
・最初に
 誤→topPointa = (void *) calloc (10 , sizeof(void *));
 正→topPointa = (void **) calloc (10 , sizeof(void *));
 
 誤→tchDataInput = (char * ) calloc (10 , sizeof(char *));
 正→tchDataInput = (char **) calloc (10 , sizeof(char *));
 ※chDataInputはchar**にすべきです。
 ※文字列型の配列をchar*の配列として表現するため。
>Voidポインタに、多種の型がぶら下がった多元配列を作り、
 ↑
 共用体を利用して実現できませんか。

例えば:
typedef struct tagPOINTER {
 union {
  void *ptr;
  int *i;
  char **c;
 } x;
} POINTER;

void **top;
POINTER *set;

// void*配列の確保
top = calloc( 10, sizeof(void*) );
// 代入用にキャスト
set = (POINTER *)top;
// int配列の確保
set[0].x.ptr = calloc( 10, sizeof(int) );
// char*配列の確保
set[1].x.ptr = calloc( 10, sizeof(char*) );

// 代入処理
set[0].x.i[1] = 2;
set[0].x.i[4] = 9;
set[1].x.c[2] = strdup( "goo" );
set[1].x.c[5] = strdup( "教えて" );

>具体的には、
>x[0][1]は、intで「2」が入っている
>x[0][4]は、intで「9」が入っている
>x[1][2]は、charでしかも文字列の配列で「goo」が入っている
>x[1][5]は、charでしかも文字列の配列で「教えて」が入っている
>x[0]は、int型の配列。X[1]は、文字列型の配列。
>というようなものです。
より。

// void**で受け取る
static void func( void **top )
{
 POINTER *get = (POINTER *)top;
 
 printf( "get[0].x.i[1] = %d\n", get[0].x.i[1] );
 printf( "get[0].x.i[4] = %d\n", get[0].x.i[4] );
 printf( "get[1].x.c[2] = %s\n", get[1].x.c[2] );
 printf( "get[1].x.c[5] = %s\n", get[1].x.c[5] );
 printf( "\n" );
}

※strdup関数はANSI-Cではないので同様な関数を自作しましょう。

投稿日時 - 2008-05-30 08:07:07

補足

一応、他の方が見られても解るように、
最終的な(共用体はなしで)ソースを載せておきます。

#include <stdio.h>  // printf
#include <stdlib.h> // callc,exit,free
#include <string.h> // strcpy

int main (void) {
  int i,j;
  // ポインタへのポインタ
  void **topPointa;

  // int時の受け渡しポインタ
  int * iDataInput;
  int * iDataOutput ;
  
  // char時の受け渡しポインタ
  char ** chDataInput;
  char ** chDataOutput;


  /************** ポインタアドレスの確保 *********/
  topPointa = (void **) calloc (10 , sizeof(void *));
  if(topPointa == NULL) {
   printf("メモリが確保できません[topPointa]\n");
   exit(-1);
  }

  /************** int型の確保 ********************/
  // int配列のメモリ確保
  iDataInput = (int * ) calloc (10 , sizeof(int));
  if(iDataInput == NULL) {
   printf("メモリが確保できません[iDataInput]\n");
   // メモリ開放
   free(topPointa);
   exit(-1);
  }

  // データの入力
  iDataInput[0] = 3 ;
  iDataInput[1] = 4 ;
  topPointa[0] = (void * ) &iDataInput;

  //int配列の取り出し
  iDataOutput = *(int **) topPointa[0];
  printf( "int: %d\n", iDataOutput[0] );
  printf( "int: %d\n", iDataOutput[1] );

  /************** char型の確保 ********************/
  // char配列 のメモリ確保
  chDataInput = (char ** ) calloc (10 , sizeof(char *));
  if(chDataInput == NULL) {
   printf("メモリが確保できません[chDataInput]\n");
   // メモリ開放
   free(topPointa);
   free(iDataInput);
   exit(-1);
  }

  for(i=0;i<10;i++)
  {
    chDataInput[i] =(char*)calloc(10 , sizeof(char));
    if(chDataInput[i] == NULL) {
     printf("メモリが確保できません[chDataInput(%d)] \n",i);
     // メモリ開放
     free(topPointa);
     free(iDataInput);
     for ( j = i ; 0 <= j ; j--)
       free(chDataInput[j]);
     break;
    }else {
      printf("chDataInput[%d]確保\n" ,i );
    }
  }

  // データの入力
  strcpy(chDataInput[1] , "hoe");
  topPointa[1] = (void * ) chDataInput;

  // char配列の取り出し
  chDataOutput = (char **) topPointa[1];
  printf( "char: %s\n", chDataOutput[1] );

  // 開放
  free(topPointa);
  free(iDataInput);
  for ( i = 0 ; i < 10 ; i++)
    free(chDataInput[i]);

  return 0;
}

投稿日時 - 2008-05-30 09:50:07

お礼

ご返答ありがとうございます。
自己解決していました。
ご指摘のとおりメモリの確保時のポインタが間違ってました。

・共用体
なるほど、確かにこういう使い方が、良いですね。
検討してみます。

投稿日時 - 2008-05-30 09:42:30

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.1

う~ん.... 型の整合性がとれてませんねぇ....
少なくとも
chDataInput[0] = &chDataInput2;
の行は確実におかしいです.
とりあえず
・全ての文で, それぞれの値がどのような型を持っているか考える
・警告をめいっぱい出すようなオプションを付けてコンパイルする
ということをやってみてください.

投稿日時 - 2008-05-29 17:48:26

お礼

お恥ずかしいです。
ポインタの使い方がおかしいのがいくらかありました。
とりあえず自己解決はしています。
ありがとうございます。

投稿日時 - 2008-05-30 09:48:58