質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.32%

C言語 argv 連結

受付中

回答 6

投稿

  • 評価
  • クリップ 0
  • VIEW 1,146

Lopn_

score 45

C言語において、argv[0]に格納されている文字を別の文字列と連結したいのですが、strcatで連結しようとするとエラーが出てしまいます

int main(int argc, char *argv[]) {

    char path;

    if (*++argv) {
        if (!strcmp(*argv, "-q")) {
            printf("help");
        }
        else {
            path = strcat("XXXX.exe ", argv[0]);
    }
    else {
        printf("exit")
    }
    return 0;
}

argv[0] を任意の文字列と連結するにはどうすればいいでしょうか?
このまま実行すると、"○○.exeは動作を停止しました"と出てしまいます

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • rubato6809

    2017/08/29 23:32

    WoodenHamletさんがご指摘の、{と}の対応がとれていない事から、そのコードはコンパイルが通ると思えません。他にも、そのコードにはおかしな点がいくつかあります。一方、"○○.exe”が出来た、のであればコンパイルが通るコードがある(あった?)はずです。質問には、そのコードをそのままコピペして提示するべきでは?

    キャンセル

回答 6

+1

まだ回答されていない話では、‘{’の対応がとれていません。

int main(int argc, char *argv[]) {

    char path;

    if (*++argv) {
        if (!strcmp(*argv, "-q")) {
            printf("help");
        }
        else {
            path = strcat("XXXX.exe ", argv[0]);  
    }   // これは2行上の '{' の閉じ
    else {
        printf("exit")
    }
    return 0;
}

つまり

int main(int argc, char *argv[]) {

    char path;

    if (*++argv) {
        if (!strcmp(*argv, "-q")) {
            printf("help");
        } else {
            path = strcat("XXXX.exe ", argv[0]);
        } else {
            printf("exit")
        }
        return 0;
    }


の状態。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

strcatの第一引数が文字列リテラルとなっています。これでは文字列結合時に文字列リテラルの先の番地に強引にデータ格納が行われます

ちなみに、main関数の引数を使うならば、argcを使って条件分岐したほうが素直です。しかもstrcatの戻り値の受け取り方もおかしいです。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

strcatの使い方
char * strcat( char *str1 , const char *str2 );

コピー先str1の末尾NULL(\0)からコピー元str2の末尾NULLまでを含めてコピーして、コピー先str1の先頭アドレスを返す。
str1とstr2を合体(append)させて新たなstr1となります。

str1を"XXXX.exe "(文字列リテラル)とすることができません。
たとえば  char str1[128] = "XXXX.exe "; とします。
また、 戻り値がアドレスなので、char path;でなく char *path; とします。

path = strcat(str1, *argv);
printf("[%s]\n",path);

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

C++14までの可変長テンプレートで文字列を連結できます。
C++17以降で畳み込み式(Fold Expressions)が利用できるようになっていますので、
その2種類も書いておきます。

#include <string>
#include <sstream>

// C++11/C++14までの可変長引数テンプレート
inline void concat_internal(std::stringstream& out) {}

template <class Head, class... Tail>
void concat_internal(std::stringstream& out, const Head& head, const Tail& ... tail)
{
    out << head;
    concat_internal(out, tail...);
}

template <class... Args>
std::string concat(const Args& ... args)
{
    std::stringstream out;
    concat_internal(out, args...);
    return out.str();
}


// C++17 以降で追加された畳み込み式
template <class... Args>
std::string concat(const Args& ... args)
{
    std::stringstream ss;
    (ss << ... << args);
    return ss.str();
}

Visual Studio ではプロジェクトのプロパティを開き、「C++言語標準」の項目の「ISO C++17 標準 (/std:c++17)」に設定を変更する必要があります。
Clang/GCCでは -std=c++17 のコンパイルオプションをつけてコンパイルする必要があります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

strcat("XXXX.exe ", argv[0]) の "XXXX.exe" は、元々のargv[0]を参照したい意図と思われますが。文字リテラルではうまくいきません。「C言語的には」たとえば char old_argv[最大バッファ長] = "XXXX.exe";(関数の外の場合はstaticを使う方がいい)などとして、最大バッファ長を越えないようにすべきです。

ただし、どちらにしても、これは元々のargv[0]と同じにはなりませんから、ps aux などで確かめても反映されません。

確かめてませんが、もしかしたら(++を使わず) strcat(argv[0],argv[1]) は動くかもしれません。
strcatの未定義動作になる可能性もありますが、一旦argv[1]のコピーを作ればC的には可能です。しかし、それでもこれはやってはいけません。バッファオーバーランが起こるでしょうが、環境によってはコマンドライン全体のバッファサイズが推定できる場合もあります。それでもそれ以外にも危険があります。

まず、argvは変更可能とC/C++の仕様にありますが、「書き換えたらどうなるか?」は環境依存です。argv[0]の後にargv[1]がある処理系も多いですから、argv[1]が破壊される可能性が高いでしょう。つまり、環境を考えて「どんな副作用があり得るか」を詳細に把握していない場合は書き換えてはならない、ということです。たとえばargv[1](可搬性をなくすのでできるだけ使うべきではありませんが)__progname という変数も書き換わるかもしれません。この変数は必ずしもargv[0]の先頭を参照しているとは限らない(basenameを参照しようとする)ので、不思議なことが起こるかもしれません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

path = strcat("XXXX.exe ", argv[0]); 

は "XXXX.exe " という文字列の直後に argv[0] 文字列(プログラム名ですか?)を書き込もうとしますが、、、

"XXXX.exe " のような文字列定数を文字列リテラルとも呼びます。普通、文字列リテラルは書き変えできないメモリ領域に配置されます。つまり、そのメモリ領域は ROM(Read Only Memory) と同様です。書き変えられないメモリに argv[0] 文字列を書き込もうとすれば、メモリアクセス違反(例外)を起こすでしょう。

対策は、配列を確保する、そこで連結作業をすることです。配列は書き変えられるメモリ領域に割り当てられますから。愚直な例を示します。

    char buffer[200]; // 処理に見合う十分な大きさにせよ
    char *path;       // ポインタ変数でないとダメ

    strcpy(buffer, "XXXX.exe ");
    path = strcat(buffer, argv[0]);

P.S.
strcpy(), strcat() にはバッファオーバーランの危険があり得ます。strcpy_s()、strcat_s() が使えるなら置き換えるのが安心でしょう。引数が異なりますので使い方を調べてください。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.32%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る