ページ 11

ポインタ

Posted: 2010年10月12日(火) 19:31
by blue
今、ポインタの問題をやっているのですが、エラーが出てどう対処すればよいのか分からないので教えてください。

最大5人の名前を格納するポインタ配列(例:char *name[5])を宣言する。
キーボードから一人ずつ名前を入力し、その名前の文字列を格納できる領域を確保してから名前の文字列を格納し、さらにそのメモリ領域へのポインタを配列に格納する。最後に、入力された人数分について、名前が格納さてているアドレスと名前の、文字列を出力するプログラムを作成せよ
<条件>
一人の名前の最大の長さは20バイト(全角文字で10文字分)とすること
アドレスの出力では、printf()における書式指定で%xを用い16進数で表記すること。
メモリ領域へのポインタを配列に格納してから文字列を格納しても構わない

↓自分が書いたソース
#include<stdio.h>
#include <stdlib.h>
int main(void){
char *name[5],*temp[5];
int i;

printf("名前を最大5人入力してください\n");
for(i=0; i<5 ;i++){

fgets(temp,20, stdin);
name[i+1] = (char *)malloc(20);
//name[i+1] = temp;
if(name[i+1] == "\0" )
continue;

printf("0x%x",*name[i+1]);
printf("%s",*name[i+1]);
}
free(name);

return 0;
}

↓エラー文
k2.c: In function ‘main’:
k2.c:10: 警告: passing argument 1 of ‘fgets’ makes pointer from integer without a cast
/usr/include/stdio.h:626: note: expected ‘char * __restrict__’ but argument is of type ‘char’
k2.c:12: 警告: assignment makes pointer from integer without a cast
k2.c:19: 警告: attempt to free a non-heap object ‘name’

Re:ポインタ

Posted: 2010年10月12日(火) 20:52
by うしお
まず、fgetsの使い方は大丈夫でしょうか?

ここで宣言されたtemp
というのは
char* temp[5];
であってchar配列ではありません。
なのでエラーになります

fgetsのシンプルな使い方は
char Buffer[21];
fgets(Buffer,21,stdin);
ということになります

また、
name[i+1]とありますが、
最初i = 0なのでこれはひとつずれていませんか?

そして、
nameへのコピーも行われていないようです

他には、mallocがループで5回よばれるにもかかわらず、
freeが1つではメモリリークを起こします
必ず1対1に対応させましょう

このようにいくつかの問題がり、
コードを見る限り、かなり混乱されているのではないかと思います
なので、
入力を取るだけ、
メモリを確保してみるだけ、
アドレスを表示するだけ、
のように、エラーの出ている問題部分を分割して取り掛かってみてはいかがでしょうか?

また、念のためですが、
malloc(20);
charは1バイトなので、これで問題はないのですが、
malloc(sizeof(char)*20);
の方が汎用性のある書き方かなと思います、ご検討ください

Re:ポインタ

Posted: 2010年10月12日(火) 22:16
by 白い時空
そもそもtempはいらないですね。

>>fgets(temp,20, stdin);
>>name[i+1] = (char *)malloc(20);
>>//name[i+1] = temp;
>>if(name[i+1] == "\0" )

ここを変えて

name=(char *)malloc(22*sizeof(char));//文字列を格納できる領域を確保
fgets(name,22,stdin);//名前の文字列を格納

if(strcmp(name, "\n")==0)//文字列の比較はstrcmp関数を使います

こうですかね。
fgetsの仕様上、文字列の最後に"\n\0"が付加されるため、文字列の長さは22です。
そのため、空打ちすると、入る文字列は"\n"になります。

あと、free(name);では駄目です。
nameにメモリを確保したんですから、1つずつfree(name);と解放しなければいけません。

Re:ポインタ

Posted: 2010年10月12日(火) 22:19
by box
> if(strcmp(name, "\n")==0)//文字列の比較はstrcmp関数を使います

\nの前後がダブルクォーテーションである理由を教えてください。

Re:ポインタ

Posted: 2010年10月12日(火) 22:47
by 白い時空
簡単に言えば
"\n"は文字列で、char*型です。
'\n'は文字で、char型です。

今回は文字列の比較なので、文字列を使うため、ダブルクォーテーションになります。

Re:ポインタ

Posted: 2010年10月12日(火) 23:10
by blue
うしおさんと白い時空さんのおかげでコンパイルは通ることができました。しかし、実行してみると
&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;5&#65533;&#65533;&#65533;&#65533;&#65533;&#996;&#65533;&#65533;&#420;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;

0x0(null)
セグメンテーション違反です (コアダンプ)
と表示されます。
まだ、おかしいみたいなのでどこを直した方がよいかアドバイスおねがいします
それから、(char *)malloc(22*sizeof(char))と(char *)malloc(20)の違いが調べてもよく分からないので教えてください
↓修正したソース
#include<stdio.h>
#include <stdlib.h>
int main(void){
char *name[5];

int i;

printf("名前を最大5人入力してください\n");
for(i=0; i<5 ;i++){

fgets(name,22, stdin); //変更
name = (char *)malloc(22*sizeof(char)); //変更
//name = ((char *)malloc(sizeof(char)*20);
//name = temp;
if(strcmp(name,"\n")==0) //変更
continue;


printf("0x%x",*name); //変更
printf("%s",*name); //変更
free(name); //変更
}
 return 0;
}

Re:ポインタ

Posted: 2010年10月12日(火) 23:38
by box
> fgets(name,22, stdin); //変更
> name = (char *)malloc(22*sizeof(char)); //変更

このように修正してください、という回答でしたか?
上下が逆ではなかったですか?

なお、fgets()の仕様は次のとおりです。
fgets()で、例えば
abc<Enter>
と入力したとき、結果を格納する配列には
a
b
c
'\n'
'\0'
が入ります。

改行'\n'と文字列終端'\0'の分を含めた領域を持っていなければなりません。
よって、有効データとして最大20バイトを確保したければ、
'\n'と'\0'を含めた22バイトの領域を定義しておかねばならない、
というのがくだんの回答の趣旨です。

画像

Re:ポインタ

Posted: 2010年10月13日(水) 00:03
by うしお
msdnのmallocを見ますと、
void *malloc(
size_t size
);
パラメータ

size

割り当てるバイト数。
とあります
charは1バイトなので
malloc(22)とmalloc(sizeof(char)*22)は同じ結果です
しかし実際intの配列やら他の構造体のメモリを確保したい場合もあります、そのときに
たとえばintなら
malloc(4*22)よりもmalloc(sizeof(int)*22)の方
とintを20個確保してるんだな、と一目で分かるのでこれはオススメです

Re:ポインタ

Posted: 2010年10月13日(水) 00:20
by blue
ありがとうございます!
理解できました。
しかし、実行するとセグメンテーションエラーは出なくなったのですがまだ&#65533;&#65533;&#65533;&#65533;&#65533;5&#65533;がでるので、もしかしたら自分のパソコンがおかしいのかもしれないので今度、学校でコンパイルしてじっこうしてみます

Re:ポインタ

Posted: 2010年10月13日(水) 00:25
by 白い時空
>>printf("0x%x",*name); //変更
>>printf("%s",*name); //変更

ここじゃないですか?
*が不要ですね。
printf("0x%x",name); //変更
printf("%s",name); //変更

Re:ポインタ

Posted: 2010年10月13日(水) 00:29
by box
> if(strcmp(name, "\n")==0)//文字列の比較はstrcmp関数を使います

わざわざstrcmp()にご登場願うまでもないと思うのですが、
そんなことないですか?

nameを先頭アドレスとする疑似2次元配列のある文字と
'\n'とをダイレクトに比べれば事足りるような気がするのですけれどね。


# って書いたけど、まあ、どっちでもいいのか…。結果さえ正しければ。

画像

Re:ポインタ

Posted: 2010年10月13日(水) 00:45
by 白い時空
boxさん

確かにそうですね。
今回は
>>if(name[i+1] == "\0" )
の間違いを指摘したかったので、strcmpにしてみました。

実際は
if(name[0]=='\n')
でも問題無いですし、寧ろこのほうが簡単ですね。

Re:ポインタ

Posted: 2010年10月13日(水) 18:08
by blue
*を抜いてみてもだめでした

Re:ポインタ

Posted: 2010年10月13日(水) 22:15
by box
最新のソースコードを載せてください。
また、どうダメだったのかも教えてください。

Re:ポインタ

Posted: 2010年10月14日(木) 14:49
by blue
学校でやってみるとできました。
自分のパソコンだと文字化けしたのでスペックが悪いのかもしれません
みなさんありがとうございました

Re:ポインタ

Posted: 2010年10月14日(木) 14:53
by softya
>自分のパソコンだと文字化けしたのでスペックが悪いのかもしれません

スペックではなくコンパイラや日本語環境問題の可能性が高いです。
お使いのコンパイラはなんでしょうか?

Re:ポインタ

Posted: 2010年10月15日(金) 18:38
by abc
これは___大学の問題ですね。
大学の宿題を人に頼りすぎるのはどうかと思いますよ。

(管理人が記事を一部削除しました)

Re:ポインタ

Posted: 2010年10月15日(金) 18:46
by def
プロ演の必須課題の期限は今日から二週間あるのですから
考えるなりTAや友達に聞くなりしましょうね^^

(管理人が一部記事を編集しました)

Re:ポインタ

Posted: 2010年10月15日(金) 18:48
by not
情報理工学部プログラミング演習2
3週目の必須課題3ー2の問題ですね?

提出物を他人に聞いて丸写し
教授にばれても知りませんよ。

Re:ポインタ

Posted: 2010年10月15日(金) 20:58
by 一般的な名前
(管理人が削除しました)

Re:ポインタ

Posted: 2010年10月15日(金) 21:07
by Dixq (管理人)
個人の特定に関係するコメントや中傷の類のコメントはどうかお控え頂けると幸いです。
複数のお名前で多くの意見に見せる行為や丁寧語ではないコメントは規約違反とさせて頂いております。
失礼ではありますが、記事の一部を編集させて頂きました。
今後とも規約を守って気持ちよく掲示板をご利用いただけると幸いです。