@ci5kym

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

const char**’ to ‘char**’ エラー

Q&A

Closed

C++でコードを書いているのですが、コンパイルエラーになってしまいます。回避方法のご教授お願いします。

int func01(void instance, int argc, char *argv);

void *minst = NULL;

int func02() {
int code;
int dat02;
const char * dat01[9];
dat01[0] = "";
dat01[1] = "aaa";
dat01[2] = "bbb";
dat01[3] = "ccc";
dat01[4] = "dddd";
dat01[5] = "eeee";
dat01[6] = "fff";
dat01[7] = "ggggg";
dat01[8] = "hhhhh";
dat02 = 9;
code = func01(minst, dat02, dat01);
}

コンパイラのエラー
function ‘int func02()’:
main.cpp:61:54: error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]

よろしくお願いします。

0 likes

1Answer

まず、↓の関数宣言ですが、

int func01(void instance, int argc, char *argv);

いわゆるmain関数的な、↓が正しい形式ですよね?
(※MarkDownの記述で*****がイタリック指定として扱われてしまったのだと思われます)

int func01(void* instance, int argc, char **argv);

その前提で話を進めささせていただきます。

さて、エラー内容はfunc01の第三引数の型変換が不正というものなので、コンパイルに通すだけなら下記のようにすればよいと思います。

code = func01(minst, dat02, (char**)dat01);

ただしこれでは根本的な解決とはいえません。
というのも、func01内部でdat01がどう処理されるかがわからないためです。

まず、const char**(※コード上はconst char * dat01[9])として宣言されたデータは、その内容が読み込み専用として扱われます。
一方でconst無しの**char****として宣言されたデータは、その内容が読み書き可能であるとして扱われます。

ご提示のサンプルの場合、dat01の配列は**"aaa"**などのリテラル(※変数を介さない直値の文字列)を保持するため、**const char****として宣言する必要があります(※リテラルはプログラム領域に保持されるので書きみ不可です)。

ですのでdat01char**にキャストしてfunc01に渡してしまうと、その内容を書き換えられてしまう恐れがあり、プログラムを実行した際に予期せぬ結果を招く可能性があります。

func01関数をご自身で実装されているのであれば、その内部で第三引数として渡したdat01への書き込みが行われていないことを確かめ、const char** argvと型を変えるのが望ましいです。

仮に、func01の関数内部でargvの内容を書き換える必要がある場合、もしくはfunc01の実装内容を変更できない場合(外部ライブラリを利用している等)であれば、書き換え可能な形式にしてデータを渡す必要があります。

例えば、下記のように上書きされてもよいように十分なバッファを確保して、dat01へ割当て、そこに文字列をコピーしてから渡します。

char * dat01[9];

// 書き込まれても良いようにバッファの確保と割当
char buf[9][256];
for( int i=0; i<9; i++ ) dat01[i] = buf[i];

sprintf( dat01[0], "" );	// バッファに書き込み
sprintf( dat01[1], "aaa" );	// バッファに書き込み
/* 省略 */
sprintf( dat01[8], "hhhhh" );	// バッファに書き込み
dat02 = 9;
code = func01(minst, dat02, dat01);	// dat01の内容は書き換え可能

C++では変数にconstをつけるかつけないかの判断がよく出てきます。
constがついていたらReadOnly、ついていなければWritableと覚えておきましょう。

1Like

Comments

  1. @ci5kym

    Questioner

    ご丁寧な解説ありがとうございました。ご指摘のように、MarkDownの記述で*がイタリック指定として扱われてしまったようです。アスタリスク2つargvの式についての質問です。

    func01は外部のライブラリの式になりますので、costへの変更がはきません。
    解説頂いた書き換え可能な変数を用意することにしました。

    おそらくfunc01は引き渡された変数を式の中で書き換える事はないと思われるので、
    作った方が適当に変数定義をしてしたのだと思います。

Your answer might help someone💌