1

文字列 S から位置 P から N 文字を削除する関数の実行可能なコードを書くことができません。どのようにそのような関数を書きますか?

void remove_substring(char *s, int p, int n) {

    int i;

    if(n == 0) {
        printf("%s", s);
    }

    for (i = 0; i < p - 1; i++) {
        printf("%c", s[i]);
    }

    for (i = strlen(s) - n; i < strlen(s); i++) {
        printf("%c", s[i]);
    }


}

例:

s: "abcdefghi"
p: 4
n: 3

出力:

abcghi

しかし、n = 0 と p = 1 のような場合は機能しません! どうもありがとう!

4

6 に答える 6

4

何人かの人々がこれを行う方法を示しましたが、彼らの解決策のほとんどは非常に凝縮されており、標準ライブラリ関数を使用しているか、単に何が起こっているのかを説明していません. これは、非常に基本的なエラー チェックだけでなく、何が起こっているのかについての説明も含むバージョンです。

void remove_substr(char *s, size_t p, size_t n)
{
  // p is 1-indexed for some reason... adjust it.
  p--;

  // ensure that we're not being asked to access
  // memory past the current end of the string.
  // Note that if p is already past the end of
  // string then p + n will, necessarily, also be
  // past the end of the string so this one check
  // is sufficient.
  if(p + n >= strlen(s))
    return;

  // Offset n to account for the data we will be
  // skipping.  
  n += p;

  // We copy one character at a time until we 
  // find the end-of-string character
  while(s[n] != 0)
    s[p++] = s[n++];

  // And make sure our string is properly terminated.  
  s[p] = 0;
}

注意すべき 1 つの警告: この関数を次のように呼び出さないでください。

remove_substr("abcdefghi", 4, 3);

またはこのように:

char *s = "abcdefghi";

remove_substr(s, 4, 3);

文字列リテラルは読み取り専用であり、それらを変更することは標準で許可されていないため、これを行うと未定義の動作が発生します。

于 2013-08-21T15:25:18.163 に答える
3

厳密に言えば、部分文字列の削除を実装していません。コードは、文字の範囲を削除して元の文字列を出力します。

注意すべきもう1つのことは、あなたの例によれば、インデックスpはCのようにゼロベースではなく1ベースであるという"abcdefghi", 4, 3こと"abcdhi"です"abcghi"

これを念頭に置いて、いくつかの変更を加えてみましょう。まず、計算が少しずれています: 最後のループは次のようになります。

for (i = p+n-1; i < strlen(s); i++) {
    printf("%c", s[i]);
}

ideone のデモ。

C のゼロから始まるインデックス スキームを使用する場合は、ループを次のように変更します。

for (i = 0; i < p; i++) {
    printf("%c", s[i]);
}
for (i = p+n; i < strlen(s); i++) {
    printf("%c", s[i]);
}

さらにif、上部の から戻るか、次を追加する必要がありelseます。

if(n == 0) {
    printf("%s", s);
    return;
}

また

if(n == 0) {
    printf("%s", s);
} else {
    // The rest of your code here
    ...
}

または完全に削除しifます。これは最適化にすぎません。コードはそれがなくても正常に動作します。

現在、 is の場合、コードは元の文字列を 2 回出力しnます0

コードで部分文字列を削除して結果を返すようにしたい場合は、次のように結果を割り当て、印刷をコピーに置き換える必要があります。

char *remove_substring(char *s, int p, int n) {
    // You need to do some checking before calling malloc
    if (n == 0) return s;
    size_t len = strlen(s);
    if (n < 0 || p < 0 || p+n > len) return NULL;
    size_t rlen = len-n+1;
    char *res = malloc(rlen);
    if (res == NULL) return NULL;
    char *pt = res;
    // Now let's use the two familiar loops,
    // except printf("%c"...) will be replaced with *p++ = ...
    for (int i = 0; i < p; i++) {
        *pt++ = s[i];
    }
    for (int i = p+n; i < strlen(s); i++) {
        *pt++ = s[i];
    }
    *pt='\0';
    return res;
}

この新しいバージョンのコードは、動的に割り当てられたメモリを返すことに注意してください。これは、free使用後に削除する必要があります。

これは ideone のこの修正版のデモです。

于 2013-08-21T14:58:20.990 に答える
2

文字列の最初の部分をコピーしてから、2 番目の部分をコピーしてみてください

char result[10];
const char input[] = "abcdefg";

int n = 3;
int p = 4;

strncpy(result, input, p);
strncpy(result+p, input+p+n, length(input)-p-n);

printf("%s", result);
于 2013-08-21T14:58:15.963 に答える
2

strcpyorのような関数を使用せずにこれを実行しようとしている場合strncpy(コメントで述べたように)、内部でどのようにstrcpy(または少なくとも 1 つの可能なバリアントが) 機能するかについて同様のアプローチを使用します。

void strnewcpy(char *dest, char *origin, int n, int p) {
    while(p-- && *dest++ = *origin++)
        ;
    origin += n;
    while(*dest++ = *origin++)
        ;
}
于 2013-08-21T15:04:46.073 に答える
1

メタコード:

  • 宛先にバッファを割り当てる
  • ソース文字列へのポインタ s を宣言します
  • ソース文字列のポインター「p-1」位置を進め、その場で宛先にコピーします
  • 「n」の位置を進める
  • 残りを目的地にコピーする
于 2013-08-21T14:55:18.337 に答える