ポインタに関する質問です2

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
そーやー

ポインタに関する質問です2

#1

投稿記事 by そーやー » 16年前

こんばんは。もうひとつ教えてください。
これは、なぜ間違いなんですか?

#include <stdio.h>

int main(void){
char test[3][10];
test[0] = "one";
test[1] = "two";
test[2] = "three";
return 0;
}

error C2440: '=' : 'char [4]' から 'char [10]' に変換することはできません。(新しい動作 ; ヘルプを参照)
この変換が可能なコンテキストはありません。
error C2440: '=' : 'char [4]' から 'char [10]' に変換することはできません。(新しい動作 ; ヘルプを参照)
この変換が可能なコンテキストはありません。
error C2440: '=' : 'char [6]' から 'char [10]' に変換することはできません。(新しい動作 ; ヘルプを参照)
この変換が可能なコンテキストはありません。

これは、strcpy関数を使えばいいことはわかるのですが、なぜ間違いなのかがわかりません。
私の解釈としては、
test[0]の先頭アドレスから順に
test[0][1] = 'o';
test[0][2] = 'n';
test[0][3] = 'e';
test[0][4] = '\0';

と代入されていくものであると思うのですが、エラーメッセージの意味すらわかりません。
どなたか、わかりやすく教えてもらえませんか?

Excelマクロと違って、文字列処理が非常に複雑なのですが、C言語は文字列操作等に向いていない言語なのでしょうか?

ねこ

Re:ポインタに関する質問です2

#2

投稿記事 by ねこ » 16年前

char変数にダブルクォーテーションで囲んだ文字列が代入できるのは宣言時のみです。
下記はいけますが
char a[ 10 ] = "ABC"
char a[ 10 ];
a = "ABC";

宣言時に
test[ 3 ][ 10 ] = { "one", "two", "three" };
とするか、宣言後
strcpy( test[ 0 ], "one" )というようにWinAPI関数を用います。

non

Re:ポインタに関する質問です2

#3

投稿記事 by non » 16年前

こうすることはできます。
int main(void){
char *test[3];
test[0] = "one";
test[1] = "two";
test[2] = "three";
return 0;
}

test[0] = "one";
は文字列リテラルのアドレスを代入しています。

>C言語は文字列操作等に向いていない言語なのでしょうか?
便利な関数はないけど、自由度はあると思います。

box

Re:ポインタに関する質問です2

#4

投稿記事 by box » 16年前

> 下記はいけますが
> char a[ 10 ];
> a = "ABC";

本当ですか?確認済みですか?

> strcpy( test[ 0 ], "one" )というようにWinAPI関数を用います。

C言語が使える環境であれば、Windowsに限らず、
どこででも使える「標準関数」です。
WinAPIとは無関係です。

MNS

Re:ポインタに関する質問です2

#5

投稿記事 by MNS » 16年前

文字列処理を簡単に行いたい、というなら、
標準テンプレートライブラリの「std::string」の使用をお勧めします。
C++の域になりますが、クラスを自作するわけではないので、
それほど難しいものではありません。
(ただし、処理速度はC言語のそれより劣ります)

ねこ

Re:ポインタに関する質問です2

#6

投稿記事 by ねこ » 16年前

失礼しました。一文抜けてました。

下記はいけますが
char a[ 10 ] = "ABC"
<このようには書けません。
char a[ 10 ];
a = "ABC";

<WinAPI
ごめんなさい。勘違いしておりました。以後気を付けます。

たいちう

Re:ポインタに関する質問です2

#7

投稿記事 by たいちう » 16年前

> (ただし、処理速度はC言語のそれより劣ります)

本当ですか?どの位劣るか示せますか?

今時の賢いコンパイラならばC言語と比べても遜色ないだろうし、
あまり賢くないコンパイラでもせいぜい数パーセント程度しか違わないと思う。
そりゃあ大量の文字列を扱うプログラムを下手に書けば遅いだろうけど、
下手に書いて遅いのはC言語も一緒だし。

「Cと比較して殆ど変わらない」というのは、あまりしっかりした根拠のない
私の主観なので、(できれば定量的な)情報があれば是非伺いたいです。

toyo

Re:ポインタに関する質問です2

#8

投稿記事 by toyo » 16年前

おっしゃるとおり
C言語は文字列操作には向いていません
Cでは配列の名前は特殊な扱いでその配列の先頭要素のアドレスになります。そしてそのアドレスは変更できません。
char a[ 10 ];
a = "ABC"; // aはa[0]のアドレスで変更できません。代入により変更しようとするとするとエラーになります。

MNS

Re:ポインタに関する質問です2

#9

投稿記事 by MNS » 16年前

>たいちうさん
私も、明確な速度の遅さを示すことは出来ません。
(そして、大した根拠もありません・・・。)
しかし、コンマ数パーセントでもstd::stringが遅いのは確かでしょう。

便利だからといって、何でもかんでもstd::stringを使い、
結果的にchar配列は使わなくなる、というのは余りよろしくないでしょう。

確かに、全くプログラムに影響しないほどの速度差かも知れませんが、
便利であることの犠牲に速度も遅くなっていく、ということを知ってほしかっただけです。
(全然伝わらなかったかも知れませんが・・・。)

lbfuvab

Re:ポインタに関する質問です2

#10

投稿記事 by lbfuvab » 16年前

ふと思ったのですが、
char *abc[3];

abc[0]="abc"
って不味くないですか?

toyo

Re:ポインタに関する質問です2

#11

投稿記事 by toyo » 16年前

問題ないですよ
char *abc;
abc = "abc";
の配列バージョンです

たいちう

Re:ポインタに関する質問です2

#12

投稿記事 by たいちう » 16年前

MNSさん

初心者の方も大勢見ている掲示板ですので、先の書き方だと
「std::stringはすごく遅い」という誤解を与えかねないと思い書き込みました。
あと本当ならばもっと詳しく聞けたらluckyと。

> しかし、コンマ数パーセントでもstd::stringが遅いのは確かでしょう。

私にはコンマ数パーセントも遅くなるとは思えないのです。
多くのケースでC言語のものと実質的に同等なバイナリが出来上がると思います。


toyoさん

> おっしゃるとおり
> C言語は文字列操作には向いていません

噛み付いてばかりですが、これもいかがなものかと。
OSを作る言語が文字列操作に向いていないわけがありませんので、
「初心者はC言語の文字列操作で躓きやすい」とか書いた方が適切かと。

sizuma

Re:ポインタに関する質問です2

#13

投稿記事 by sizuma » 16年前

ぼくもふと疑問が。
こういう2次元配列で管理するときのアドレスってどうなってるんだ?
って思いました。

確認してみると、あーなるほど、と納得。
最初char*配列のメモリを連番で確保して、そのあとにchar*のメモリを連番で確保するんですね
char*が4バイトっていうのも知らなかった・・・
勉強不足でした


>たいちうさん

>OSを作る言語が文字列操作にむいてないわけありませんので、

OSについて全然わからないから、答えていただいてもわからないかもしれないんですが・・・
OSを開発するときに出てくるCの文字列操作の利点というのはなんなのでしょうか?

やはりメモリを他の言語より細やかに扱えるから??

あと
OSを作る → 文字列操作に向いていないわけがない、という流れがわからないです
OSを作るのってプロセスの管理を作るものだと理解してました

知識がない人には説明しきれないような質問かもしれないんで、
お忙しいときは無視してください。


>噛み付いてばかりですが
いろいろな視点から自分の理解より深い部分を論議してもらうととても勉強になります。
いつも勉強させて頂いてます。

たいちう

Re:ポインタに関する質問です2

#14

投稿記事 by たいちう » 16年前

> OSを作る → 文字列操作に向いていないわけがない、という流れがわからないです
> OSを作るのってプロセスの管理を作るものだと理解してました

OSを作る → 何でもできる → 文字列操作に向いていないわけがない

という程度の意味です。プログラマで例えると、文字列操作もろくに
できないような人がOSを自作できるはずがないと思います。
同様に考えて、文字列操作もろくにできないような言語では、
OSを作れるはずがないでしょう。

ちなみに私は文字列操作は十分できますが、OSを作るレベルには
程遠いプログラマですので、この位の回答で勘弁。

ねこ

Re:ポインタに関する質問です2

#15

投稿記事 by ねこ » 16年前

何か気になる話題があったので横から顔出してみます。
まず、処理速度に関しては私も「結構遅くなる」と聞いた覚えがあります。
実際どれくらい遅くなるのか把握してなかったので簡単なチェックを行ってみました
// チェック簡略用マクロ( A:ループ回数(平均値計算用), B:ループ回数 )
#define CHECK_TIME_PREV( A, B )					\
{								\
	LONG nArrTime[ A ];					\
	LONG nCount = A;					\
	LONG nTotalTime = 0;					\
								\
	LONG nTime1 = 0, nTime2 = 0;				\
								\
	for( LONG ii = 0; ii < nCount; ii++ )			\
	{							\
		nTime1 = GetNowCount();				\
		for( LONG jj = 0; jj < B; jj++ )		\
		{

#define CHECK_TIME_AFTER( A )					\
		}						\
		nTime2 = GetNowCount();				\
								\
		nArrTime[ ii ] = nTime2 - nTime1;		\
		nTotalTime += nArrTime[ ii ];			\
	}							\
	TRACE2( "%s:AvgTime:%lf", A, (double)nTotalTime / (double)nCount ); \
}
※TRACE2は出力ウィンドウに表示するためのマクロです

// チェック処理
#define AVG_CNT 20
#define  DO_CNT 100000

// 定義、サイズ指定無し
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
std::string str1;
CHECK_TIME_AFTER( "std定義1" );

// 定義、サイズ指定無し
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
std::string str1( 64, 'a' );
CHECK_TIME_AFTER( "std定義2" );

// 定義初期化無し
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
char cTemp[ 64 ];
CHECK_TIME_AFTER( "chr定義1" );

// 定義初期化有り
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
char cTemp[ 64 ] = "a";
CHECK_TIME_AFTER( "chr定義2" );

// 代入
std::string str1;
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
str1 = "ABC";
CHECK_TIME_AFTER( "std代入" );

// 代入
char cTemp[ 64 ];
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
strcpy( cTemp, "ABC" );
CHECK_TIME_AFTER( "chr代入" );
<結果> ※投稿時、小数点位置で調整しています。
std定義1:AvgTime: 58.500000
std定義2:AvgTime:708.850000
chr定義1:AvgTime: 0.250000
chr定義2:AvgTime: 1.800000
std代入 :AvgTime: 58.200000
chr代入 :AvgTime: 0.600000

こんなチェックで良いのかな・・・と感じますが
チェックした感じ、結構な差があるように思えます。
どこに負荷があるかは内部ロジックを調べてみないと分かりませんが
それなりに負荷のあるプログラムでは、stringクラスは避けた方が処理効率は上がりそうですね。

たいちう

Re:ポインタに関する質問です2

#16

投稿記事 by たいちう » 16年前

コンパイラとコンパイル条件を書いてください。
まさかデバッグモードではないですよね。

たいちう

Re:ポインタに関する質問です2

#17

投稿記事 by たいちう » 16年前

ソースを読みましたが、多分デバッグモードでの実行結果ですね。
比較対象自体が最適化でなくならないようなコードで、
実行時間で最適化をかけて比較する必要があります。

toyo

Re:ポインタに関する質問です2

#18

投稿記事 by toyo » 16年前

char cTemp[ 64 ];
で文字数を制限してるのは公平ではないでしょう
char もmallocで確保する処理を入れて比べたほうがいいのでは

ねこ

Re:ポインタに関する質問です2

#19

投稿記事 by ねこ » 16年前

VC2008 Exp-Releaseです。
他はデフォルトからDXLIBのコンパイルが通るように変更している程度かな。

<まさかデバッグモードではないですよね。
何か結果に疑問でもあるんでしょうか?
仮にデバッグモードだとしても両者の差はそこまで変わらないと思いますが・・・

<ちょっと訂正
ループ数10万⇒100万の間違いでした。結果は大体1/10になっただけですが・・・

ねこ

Re:ポインタに関する質問です2

#20

投稿記事 by ねこ » 16年前

>toyo様
最初はそうしていたのですが
今回の観点は両者の使い分けと速度にあると思ったので
常にcharをmallocで確保する、という条件は必要無いと感じました。
勿論これは私見ですので、結果に不満等ある場合は別途比較を示していただければと思います。

<文字数制限
デフォルトコンストラクタでどれくらいの文字数文確保されているのかが分かりません。
それが分かると合わす事も出来るんですが・・・

ねこ

Re:ポインタに関する質問です2

#21

投稿記事 by ねこ » 16年前

すいません、訂正します。
プロジェクトの設定がおかしかったため再度記述します。

ねこ

Re:ポインタに関する質問です2

#22

投稿記事 by ねこ » 16年前

設定変更後、ウィルスチェックとか監視ソフトとか止めると凄く異なる結果になったので訂正します。
// 定義初期化有り
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
char* cTemp = new char [ 64 ];
CHECK_TIME_AFTER( "chr定義3" );
// 定義初期化有り
CHECK_TIME_PREV( AVG_CNT, DO_CNT );
char* cTemp = (char*)malloc( 64 );
CHECK_TIME_AFTER( "chr定義4" );
std定義1:AvgTime:0.000000
std定義2:AvgTime:65.700000
chr定義1:AvgTime:0.000000
chr定義2:AvgTime:0.000000
chr定義3:AvgTime:112.100000
chr定義4:AvgTime:111.500000
std代入:AvgTime:2.000000
chr代入:AvgTime:0.000000

10万回の結果です。一部ループを何回にしても1以上になりませんでした。

また、文字数を128⇒256にしたところで
<128>
std定義2:AvgTime:65.000000
chr定義3:AvgTime:121.000000
chr定義4:AvgTime:119.000000
<256>
std定義2:AvgTime:367.000000
chr定義3:AvgTime:132.000000
chr定義4:AvgTime:131.000000
このように所要時間が増えました。
デフォルトでは128程度とっているため、それを超えると再度メモリを取得しているのかと予想します。

sizuma

Re:ポインタに関する質問です2

#23

投稿記事 by sizuma » 16年前

>たいちうさん

回答ありがとうございます。

OS作りってなんだか魅力的なものみたいですね。
夏休みにでもテキスト買い込んでOSについて勉強してみようと思います

脱線した質問失礼しました

閉鎖

“C言語何でも質問掲示板” へ戻る