結果的に
char strs[10][10];
と同じ領域を確保しようというものです。
ちなみにコンパイル時に
warning C4700: local variable 'strs' used without having been initialized
という警告がでますが、きちんと動作します。
この警告の意味することがわからないのと、今回のようなアルゴリズムとして適当なものであるのか教えてほしいです。
↓以下ソース↓
#include <stdio.h>
#include <stdlib.h>
int main(){
char **strs;
*strs = (char *)malloc(10);
for( int i=0 ; i < 10 ; i++ ){
strs[i] = (char *)malloc(10);
}
strs[0] = "maiueo";
strs[1] = "kakiku";
printf("%s", strs[0] );
printf("%s", strs[1] );
for( int i=0 ; i < 10 ; i++ ){
free(strs[i]);
}
free( *strs );
return 0;
}
No.1ベストアンサー
- 回答日時:
>*strs = (char *)malloc(10);
の部分strs は、ポインタへのポインタですけど、
その指し示すポインタがありません。(なので初期化せずに使っていると怒られます)
>strs[0] = "maiueo";
>strs[1] = "kakiku";
mallocで確保したのとは別のポインタが代入されているので、
このあとのfree が(正常には)できません。
以上に注意して書き直したもの
----------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char **strs;
strs = (char **)malloc(sizeof(char*)*10);
for( int i=0 ; i < 10 ; i++ ){
strs[i] = (char *)malloc(10);
}
strcpy(strs[0],"maiueo");
strcpy(strs[1], "kakiku");
printf("%s\n", strs[0] );
printf("%s\n", strs[1] );
for( int i=0 ; i < 10 ; i++ ){
free(strs[i]);
}
free( strs );
return 0;
}
ソースありがとうございます。
や、やっと理解できました。
ソースを見ながら考えて、やっとこさわかりました。
概念としては
strs
(char *)[0]--"string"
(char *)[1]--"string"
(char *)[2]--"string"
(char *)[3]--"string"
といったかんじでしょうか。
しかし、よくよく考えてみると、私のソースでも
(char **)strs
↓(アドレス)
(char *)[0]--"string0"
(char *)[1]--"string1"
(char *)[2]--"string2"
(char *)[3]--"string3"
となり、この場合[0]を開放すると、"string0"の領域のみが開放されるのであり、[0]はいぜんとして(char *)のままだと思います。よってstrs領域は開放されないままであり、最後にfree(strs)としても成功するような気が。
それでも警告をださずにコンパイルするとなると、BLUEPIXYさんの示してくれたソースのようにする以外はなさそうですが、、、
私の考えはいぜんとして間違ったままでしょうか?
No.4
- 回答日時:
buf[10][10]ではわかりにくいので、
char buf[100][80];
で説明します。
「配列へのポインタ」を1個宣言します。
char (*p)[80];
malloc関数で領域を取ります
p = (char (*)[80])malloc(100*80);
そうすれば、
p[1][2]='A';
などのように、ご自由にお使い下さい。
プログラムの中で、
strs[0] = "maiueo";
strs[1] = "kakiku";
このような代入をしたいのであれば、それは「ポインタ配列」宣言です。
char **strs;
strs = (char **)malloc(10*sizeof(char *));
strs[0] = "ABCDE";
strs[1] = "FGHIJ";
普通は、
strs[0] = (char *)malloc(計算された文字数);
のように、さらにmalloc関数を使います。
(1文字1バイトの場合)。
p = (char (*)[80])malloc(100*80);
こ、こんな使い方もできるんですね・・。
なんとなく読むことくらいはできるのですが、こんな表現はじめて見ました。
これで素直にp[0]からp[n]まで100個ずつ割り当てられるなんて~すごい。
ちょっと私のレベルを超えた表現みたいですが、参考になりました。ありがとうございます。
それと、
strs[0] = "maiueo";
としてたのは、私のよく犯すミスで、本当はstrcpyでコピーしたような感じを頭で思い描いてソースかいていたりします・・。
質問でまぎらわしい間違いをしてすみませんでした。
No.3
- 回答日時:
>この場合[0]を開放すると、…
#1で言う、「その指し示すポインタがありません。」は、
>*strs = (char *)malloc(10);
で、確保された領域のアドレスはどこに格納されているのか?
ということが問題です。
例えば、
char area1[10];
char *p1;
の時
p1=&area1[0];
とか
p1=area1;
とするわけですが、この場合は、
area1[10]の領域の先頭アドレスがポインタp1 に格納されるワケです。
ここで、
char **pp1;
とした場合、
pp1=&p1;
とした場合は、
*pp1=area1;
は、p1=area1 と同じ意味になりますが、
pp1=&p1;
とせずに
*pp1=area1;
とすると、まだその指している場所(先述で言うとp1 にあたる)がありません。
by the way...
「このあとのfree が(正常には)できません」ですが
strs[0] = (char *)malloc(10);
とした場合、strs[0] には、malloc で確保した領域のアドレスが入っています。
これは、
free(strs[0]) で解放できます。
が、しかし
strs[0] = "maiueo";
とした場合には、strs[0] には、定数としてあらかじめ確保された領域のアドレスが設定されているのであって
free("maiueo");
ができないように
strs[0] = "maiueo";
としてしまったら
free(strs[0]) ;
とはできません
あ、なるほど。
そもそもstrcpyを使ってコピーするということを忘れてたんですね。
char **ppstr;
があって
*ppstr = (char *)malloc( 10 );
としたのでは、最終的に指し示す部分に割り当てられるのに対して
ppstr = (char **)malloc( (char *) * 10 );
とすれば、2次元配列の列を割り当てることができる、ということだったんですね・・。
ありがとうございます。頭スパークしてたみたいで、こんな単純なことがわからなかったみたいです。
No.2
- 回答日時:
#1の方の指摘されている内容以前に..
> char strs[10][10];
ということであれば、
char (*strs)[10] = malloc(sizeof(char[10][10]));
ではないでしょうか?
回答どうもです。
いまだに#1の方の書いてある内容が把握できず考え中なのですが、動的に割り当てるのは使用するメモリは極力抑えておいて、必要になったら後から付け足していくためのものなので、列と番を同時に宣言しては意味がないのです。
例えば、
(char *)[0]
(char *)[1]
.
.
(char *)[50]
といったかんじでメモリ確保しておき、必要になったらそれぞれをそれぞれの長さでメモリ確保する必要があるので。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# const char** p;のとき、free(p)でC4090エラーとなるのはなぜですか 3 2023/03/31 16:28
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# c言語でユーザ関数を利用して入力された文字列を反転させるプログラムを作りたいです。 3 2023/01/29 19:47
- C言語・C++・C# 宣言する関数の形が決まっている状態で、 str1とstr2の文字列をこの順に引っ付けてstrに保存し 2 2022/05/30 18:21
- C言語・C++・C# c言語 プログラムのエラー 1 2023/02/11 20:31
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# C言語で再起関数とポインタを用いて文字列反転をする方法がわかりません。 4 2023/04/29 20:32
関連するカテゴリからQ&Aを探す
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
char*を初期化したいのですが
-
C言語のintとcharの違いってな...
-
strcat関数を自作したいです
-
CStringからchar*への型変換に...
-
エクセルのMID関数は、C言語では?
-
動的メモリの初期化方法について。
-
コマンドライン引数
-
文字列の途中から途中までを抽出
-
文字型配列に格納した空白の切捨て
-
文字列str内の全ての数字を...
-
C言語を用いた環境変数の作成/...
-
文字列配列を動的に割り当てる...
-
C言語にて構造体のメンバがNULL...
-
char** buffer (このような2...
-
char 文字列型 の表現範囲が-12...
-
文字列の演算
-
文字列のswap
-
char形配列の整数を抜き出したい
-
new charとnew char[N]の違いは?
-
C# ポインタ アクセス違反
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語のintとcharの違いってな...
-
char*を初期化したいのですが
-
C言語にて構造体のメンバがNULL...
-
CStringからchar*への型変換に...
-
strcat関数を自作したいです
-
new charとnew char[N]の違いは?
-
csvファイルをfscanfで読み込む...
-
char型にint型の数値を代入する。
-
動的メモリの初期化方法について。
-
C言語で文字列をかえす正しい書...
-
文字列str内の全ての数字を...
-
char 文字列型 の表現範囲が-12...
-
DWORDとcharの変換
-
fstream型オブジェクトを関数の...
-
C言語のプログラムについてです
-
小数点入りの文字列をfloat型に...
-
szとlpszの違い
-
const char* s1とただのchar s1...
-
文字列内の数字削除
-
c言語でポインタ変数を用いた配...
おすすめ情報