2016-10-09 2 views
0

私のプログラムは、2つの文字列を読み込み、新しい文字列(3番目)が最初の文字列として1番目の文字列、2番目の文字列最初の文字列の2番目の文字列など。長い文字列の余分な文字は、単に最後に置かれます。配列に何も割り当てられていない関数(ポインタ演算を使用)

ここでコード:

#include <stdio.h> 
#include <string.h> 
#define N 1000 

void merge(char *s3, char *s1, char *s2); 
int read_line(char *str, int n); 

int main(void) 
{ 
    char a[N], b[N], c[N]; 
    int num_chara, num_charb, num_charc, i; 


    printf("Enter the first set of characters: "); 
    num_chara = read_line(a, N); 
    printf("Enter the second set of characters: "); 
    num_charb = read_line(b, N); 

    num_charc = num_chara + num_charb; 

    merge(c, a, b); 
    printf("Output: "); 
    for (i = 0; i < num_charc; i++) 
     printf("%c", c[i]); 
    printf("\n"); 

    return 0; 
} 

void merge(char *s3, char *s1, char *s2) 
{ 
    size_t low_limit, up_limit; 
    int i; 

    if (strlen(s1) < strlen(s2)) 
    { 
     low_limit = strlen(s1); 
     up_limit = strlen(s2); 
    } 
    else 
    { 
     low_limit = strlen(s2); 
     up_limit = strlen(s1); 
    } 

    for (i = 0; i < low_limit; i++) 
    { 
     s3 = s1 + i; 
     s3++; 
     s3 = s2 + i; 
     s3++; 
    } 

    if (strlen(s1) < strlen(s2)) 
    { 
     for (i += 1;i < up_limit; i++) 
     { 
      s3 = s2 + i; 
      s3++; 
     } 
     *s3 = '\0'; 
    } 
    else 
    { 
     for (i += 1;i < up_limit; i++) 
     { 
      s3 = s1 + i; 
      s3++; 
     } 
     *s3 = '\0'; 
    } 
} 

私の問題はmain()でこれを呼び出すときに3番目の文字列が空であるかのように、何で3番目の文字列の結果を印刷することは、印刷されているということです!

1番目と2番目の文字列をうまく印刷できたので、印刷する方法は正しいです。私はここで間違っていることを理解することはできません。各ステップの論理が意味をなさないからです。私はC言語の新機能ですが、ポインタの算術演算は依然として私にとっては厄介です。

編集:

1)私はこれをコンパイルすると、私のエラーや警告(GCC)を与えないことを驚いています。

2)s3の割り当てを* s3と*(s1またはs2 + i)に置き換えると、このプログラムはほとんどの場合動作します。出力の最後の数文字は予期しない結果になっていますが、ありがとうChristophe、しかし私はこのプログラムで配列インデックスを使用することを避けようとしています。

+0

プログラム全体/コード全体がもっとあれば役に立ちますが、そうしないと、 's3'がすべてのデータを保持するのに十分な大きさであることを確認できますか? – RastaJedi

+0

's3は別のメモリバッファであるはずですか?ほとんどの場合、 'main'とその関数の呼び出し方法を表示するだけです。 AFAICSではNUL文字以外は 's3'に何も書きません:' * s3 = '\ 0'; '。そして、それは 's3'が' s1'または 's2'のどちらかを指しているので間違っているかもしれませんので、それらを上書きしようとしています。 – kaylum

+0

's3 = s1 + i;'は完全に間違っています。おそらく '* s3 = *(s1 + i);'でなければなりません。このエラーは複数回発生します。 –

答えて

1

おっと! merge()では、ポインティングされた値を代入するのではなくポインタ演算を行っています。これは完全に合法であるので、コンパイラが文句を言わないだろう。

をたとえば:

... 
    s3 = s1 + i; // simply changes the pointer, not the zone pointed to 
    s3++;   // now the pointer 3 points to the address of a[i+1] 
    ...    // the content of the string pointed by s3 is left unchanged 

これを解決するには、あなたが*とか[]とのいずれかのポインタを間接参照しなければなりません:

... 
    *s3 = s1[i]; // works on the character pointed to and not the pointer itself 
    s3++; 
    *s3 = s2[i]; // you could combine the two lines with *s3++ = s2[i] 
    s3++; 
    ... 

重要なお知らせ:あなたの関数merge()は非常に危険です。この関数は配列のサイズについて何も知らない。 abN-1の文字で終わり、末尾が'\0'の場合、この関数は2*N-1文字をcに書き込むため、バッファオーバーフローが発生してメモリが破損します。致命的な脆弱性の2つの簡単な修正:

  • 変化nはs3アレイのサイズであろうvoid merge_s (char *s3, char *s1, char *s2, size_t n)からc変化
  • 2*Nの関数シグネチャのサイズ。

編集:

追加問題:1つの文字列が他方よりも大きい場合は、共通の長さを超えて最初の文字をスキップします。これは、追加のfor-loopsをfor (i+=1;...)で開始しますが、iは既にコピーする正しい文字を指しているからです。これらの2つのループを変更するだけですfor (;...)

ポインタ演算を使用することをお勧めすると、s1[i]*(s1+i)と同じです。ちなみに、奇妙に聞こえるかもしれませんが、それはi[s1]と同じです!

文字列の末尾を超える不規則な文字は、長さが正しくないためにNULL終端文字を出力する原因となる可能性があります。 read_line()をチェックして、ヌルターミネータを数えない文字列の長さを返すことを確認してください。しかし、それはあなたのデバッガで簡単に修正できるはずです。

関連する問題