-3

独自のバージョンの strcat を作成しようとしています (「追加」と呼びます)。ここに私が持っているものがあります:

#include <stdio.h>

int main() {

  char *start = "start";
  char *add = "add";
  append(start, add);
  printf(start);

}

void append(char *start, char *add) {
  //get to end of start word
  char *temp = &start;
  while (*temp != '\0') {
    temp++;
  }
  *temp = *add;
  while (*temp != '\0') {
     *temp = *add; 
  }
}

コンパイルすると、3 つの警告とエラーが表示されます。

1) 警告: 関数 'append' の暗黙の宣言は C99 では無効です

2) 警告: フォーマット文字列は文字列リテラルではありません (安全でない可能性があります)

3) エラー: 'append' のタイプが競合しています

メイン内の追加関数に渡す引数が、その下の関数定義とどのように競合するかわかりません。

4) 警告: 型 'char **' の式で 'char *' を初期化する互換性のないポインター型。削除する &

なぜここを削除したいの&ですか?char適切なメモリアドレスへのポインタを一度に宣言して初期化できると思いました。

どんな助けでも大歓迎です。

4

4 に答える 4

3

1) 警告: 関数 'append' の暗黙の宣言は C99 では無効です

3) エラー: 'append' のタイプが競合しています

append()使用する前にのプロトタイプを提供しなかったためです。関数を使用する前に、関数の前方宣言を追加する必要があります。追加

void append(char *start, char *add);

main()関数定義の前または前に置くmain()

次に、

 char *start = "start";
 char *add = "add";

startおよび文字列リテラルaddへのポインタです。それらは通常、読み取り専用メモリに配置されます。つまり、内容を変更することはできません。そうしようとすると、未定義の動作が発生します。

次に、に関して

2) 警告: フォーマット文字列は文字列リテラルではありません (安全でない可能性があります)

printf(start);

この場合の使い方は間違っています。次のように使用する必要があります

printf("%s\n", start);

詳細については、のマニュアル ページを確認してprintf()ください。

そして最後に、

4) 警告: 型 'char **' の式で 'char *' を初期化する互換性のないポインター型。削除する &

のせいです

char *temp = &start;

次のようなものを使用する必要があります

char *temp = start;   //start is a char *, no need for & here

注: の推奨される署名はmain()ですint main(void)

于 2015-04-24T20:51:08.863 に答える
2

その短いコードには複数の問題があります。まずあなたが持っている

警告: 関数 'append' の暗黙の宣言は C99 では無効です

この警告の意味は、関数を使用する前に関数を宣言する必要があるということです。関数を使用する前に関数を宣言しないと、コンパイラはその引数と戻り値の型を推測する必要がありますが、多くの場合、その推測はうまくいきません。

次の警告に続きます。

警告: フォーマット文字列は文字列リテラルではありません (安全でない可能性があります)

これは、 に文字列変数を指定したためですprintf。これは、警告が示すように安全ではありません。たとえば、ユーザーからの入力を読み取り、その入力をフォーマット文字列として使用する場合を考えてみてくださいprintf。ユーザーが入力文字列に書式コードを追加するのを妨げるものは何ですか? そして、引数を渡さないので、それらの形式の引数はどこから来るのでしょうか?

そして今、エラー:

エラー: 'append' のタイプが競合しています

これは、コンパイラが関数の引数または戻り値の型を間違って推測したという最初の問題が原因です。


次に、コンパイラ エラーや警告として表示されない別の主要な問題、つまり未定義の動作について説明します。

問題は、変数startadd変数が文字列リテラルを指していることです。文字列リテラルは読み取り専用です(実際、文字列リテラルは変更不可能な文字の配列へのポインターです)。最初の問題は、これらの配列の内容を変更しようとすることです。2 つ目は、配列が必要なだけの大きさであり、そのメモリの外に書き込んでいるということです。これらの問題はどちらも未定義の動作の原因です。

于 2015-04-24T20:55:18.273 に答える
2

しかし、これは簡単な部分であり、コンパイラーが検出できるものです。

悪い点は、あなたがstartas として宣言したようchar *start = "start"に、6 文字 (5 文字 + 終端の null) の配列しか指していないことです。

そのため、最後に追加しようとするaddと、未定義の動作が発生します(配列を超えて書き込むため)! その場合、他の可能性がある場所にメモリを書き込んでいます => プログラムが壊れたり、セグメンテーション違反を起こしたりする可能性があります。

于 2015-04-24T20:55:25.740 に答える
1

C99 では、宣言の方法がかなり制限されています。

Souravが言ったように、1と3はappend()、ファイルで宣言される前に関数が使用されていることが原因であり、コンパイラが暗黙の宣言を生成します。append()上記の関数を移動しmain()て修正します (または関数プロトタイプを追加します)。

4 は次の行が原因です。char *temp = &start;

tempchar**のアドレスを取得しているため、実際には aです。char*

于 2015-04-24T20:55:46.373 に答える