2017-01-23 23 views
0

Cで汎用印刷配列関数を作成しようとしていて、何とか文字列配列でうまく動作しません。 ここではメインです:C汎用印刷配列関数 - 文字列配列の印刷

#define LEN 20 

typedef struct 
{ 
char name[LEN]; // worker's name 
int salary; // worker's salary 
char **childArr; // array of children names 
int numChildren; // number of children 
}Worker; 

void printArray(void* arr, int size, int typeSize, void (*print)(void*)); 
void printString(void* s); 
void printWorker(void* worker); 

void main() 
{ 
// arrays of children's names 
char *chBamba[] = { "Bambale1", "Bamb2", "Bamb3", "Bambook4", "Bambookle5" }; 
char *chBisli[] = { "Bislile1", "Bischick2", "Bislile3", "Bis4"}; 
int nBamba = sizeof(chBamba)/sizeof(*chBamba); 
int nBisli = sizeof(chBisli)/sizeof(*chBisli); 
// array of workers 
Worker a[] = { {"Printf", 10, NULL, 0} , {"Bisli", 20, chBisli, nBisli}, 
{"TapooChips", 3, chBamba, nBamba}, {"Bamba", 19, chBamba, nBamba} }; 

printArray(a,sizeof(a)/sizeof(Worker),sizeof(Worker),printWorker); 

} 

と機能:

void printArray(void* arr, int size, int typeSize, void (*print)(void*)) 
{ 
    int i; 
    for (i=0;i<size;i++) 
    { 
     print((char*)arr+i *typeSize); 
    } 
    printf("\n"); 
} 

void printString(void* s) 
{ 
    char* str = (char*)s; 
    printf("[ %s ]",*str); 
} 

void printWorker(void* worker) 
{ 
    Worker* w = (Worker*)worker; 
    printf("%s\t %d...(%d) ",w->name,w->salary,w->numChildren); 
    if (w->numChildren != 0) 
     printArray(w->childArr,w->numChildren,LEN,printString); 

    printf("\n"); 
} 

二労働者のデータを印刷し、「子供」配列、コードブレークに行く後...

どんな考え?どのように私はそれを修正することができますか?

この編集後:printArray(w->childArr,w->numChildren,sizeof(w->childArr[0]),printString);

と、この:printf("[ %s ]",str);

を私は今、次のプリントを持っている: img1

+0

まあ、 'printfの(「%sキーを」、* STR);'確かに良いではありません、そして、あなたのコンパイラがそうあなたを伝える大きな脂肪の警告を投げている必要があります。 'str'は' char * 'なので、' * str'は 'char'であり、'%s'とうまく対応しません。基本的には、あなたがcharへのポインタを約束しcharを与えたとき、あなたは 'printf'に嘘をつきました。そして、fyi、 'char * str =(char *)s;のキャストは必要ありません。 like-constの 'void * 'にキャストしたり、キャストしたりするのは自動です。 – WhozCraig

+0

インデックス作成に正しいタイプの 'size_t'を使用しません。そして、あなたは何もしないで 'Worker * w =(Worker *)worker; =>' Worker * w = worker; ' – Stargateur

+0

@Stargateur - コンパイラには関係ありません。 – LjTiNo

答えて

1

この行をここに:

printArray(w->childArr,w->numChildren,LEN,printString); 

あなたにLENを渡します配列内の要素のサイズ。これはおそらく配列要素の大きさよりも大きくなります。これにより、printArrayのループが配列境界外に移動します。アクセスは未定義の動作です。

あなたの配列には文字列へのポインタが含まれています。 sizeof(char*)に合格する必要があります。それとも、もっとD.R.Y的に:

printArray(w->childArr, w->numChildren, sizeof w->childArr[0], printString); 

あなたprintString関数が間違った型変換を行います。 printArrayは、現在の要素へのポインタをコールバックに渡すことを忘れないでください。 char*の配列を反復処理するので、char**を渡します。このことを念頭に置いて:

void printString(void *vpStr) { 
    char **pStr = vpStr; 
    printf("[ %s ]", *pstr); 
} 
+0

まあ、それは問題の半分を解決しました...今それは印刷されますが、私は印刷するように頼んだものではありません...あなたは私の質問の編集を見ることができますか? – LjTiNo

+0

@LjTiNo - 私の編集を参照してください。タイプ消去は細部に注意を払う必要があります。 – StoryTeller

+0

私はそれをchar ** str =(char **)sで行う必要がありました。 (idkなぜ私のコンパイラはキャストなしで私をさせません..)しかしそれは動作します!あなたは素晴らしいです! :) – LjTiNo

0

だけで参照するために、使用している方法は、これは伝統的にCで行われている。しかし、現代Cであなたがより良い方法では、このような汎用的な関数を書くことができる方法です。タイプは安全でなくて関数ポインタのために必要:

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

#define print_array(data, n)   \ 
    _Generic((*data),     \ 
      int: print_int,   \ 
      char: print_char)(data,n) \ 


void print_int (const int* data, size_t n) 
{ 
    for(size_t i=0; i<n; i++) 
    { 
    printf("%d ", data[i]); 
    } 
} 

void print_char (const char* data, size_t n) 
{ 
    for(size_t i=0; i<n; i++) 
    { 
    printf("%c ", data[i]); 
    } 
} 



int main (void) 
{ 
    int int_array [3] = {1, 2, 3}; 
    const char* char_array = "hello world"; 

    print_array(int_array, 3); 
    printf("\n"); 
    print_array(char_array, strlen(char_array)); 
    printf("\n"); 

}