3

おそらく、C初心者からの愚かなポインターの問題です。しかし、これを理解できませんでした。どうやら私のスタックフレームが壊れているようです。割り当てはほとんど無関係のように見えますが、かなり基本的な I/O 演習です。1 回の読み取りで構造体の配列を読み込もうとしています (fread() などの高度な I/O 関数は使用できません)。

#include "A2_Phase2.h"

void read_directory(Cdir directory[], int cnt) 
{
    int fd;
    char filename[] = "RandomStructDir.bin";

    fd = open(filename, O_RDONLY, S_IRWXU);
    if (fd < 0)
        perror(strcat(filename, " failed to open."));

    if (read(fd, &(directory[0].code[0]), sizeof(Cdir) * cnt) < 0) {
        perror(strcat(filename, " could not be accessed."));
    }

    close(fd);
}

int binary_search(Cdir directory[], char *key, int l, int r) {

    int mid = (int) r / 2;

    if (strncmp(key, directory[mid].code, 3) < 0)
        return binary_search(directory, key, l, mid - 1);
    else if (strncmp(key, directory[mid].code, 3) > 0)
        return binary_search(directory, key, mid + 1, r);
    else
        return mid;
}

int main(int argc, char *argv[]) 
{
    int COUNTRY_COUNT = atoi(argv[1]);
    printf("%d", COUNTRY_COUNT);

    Cdir *directory = (Cdir *) malloc(sizeof(Cdir) * COUNTRY_COUNT);
    read_directory(directory, COUNTRY_COUNT);
    binary_search(directory, "ZWE", 0, 238);
    free(directory);
}

GDB 経由で次のエラーが表示されます。

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400940 in binary_search (
    directory=<error reading variable: Cannot access memory at address 0x7fffff7feff8>, 
    key=<error reading variable: Cannot access memory at address 0x7fffff7feff0>, l=<error reading variable: Cannot access memory at address 0x7fffff7fefec>, 
    r=<error reading variable: Cannot access memory at address 0x7fffff7fefe8>)
    at A2_Phase2.c:19
19  int binary_search(Cdir directory[], char *key, int l, int r) { 

ありがとう!

4

4 に答える 4

5
int COUNTRY_COUNT = atoi(argv[1]);

>= 238プログラムへの引数として国の数を読み取りますが、これが呼び出すときであるという仮定を後でハードコードします

binary_search(directory, "ZWE", 0, 238);

試してみませんか

binary_search(directory, "ZWE", 0, COUNTRY_COUNT-1);

代わりは?binary_search関数には、次のように書き直すことができるいくつかのエラーもあります。

int binary_search(Cdir directory[], const char *key, int l, int r)
{
    int mid = (r + l) / 2;
    int cmp = strncmp(key, directory[mid].code, 3);
    if (l >= r) {
        if (cmp == 0)
            return l;
        return -1;
    }
    if (cmp < 0) 
        return binary_search(directory, key, l, mid - 1);
    else if (cmp > 0)
        return binary_search(directory, key, mid + 1, r);
    else
        return mid;
}

主な変更点は

  • の計算midlr
  • (キリレンコが指摘したように)一致するものを見つけることができないことを認識してください。この場合は -1 を返します
  • への呼び出し回数を減らしますstrcmp。非常にマイナーですが、コードがより明確になり、検索のパフォーマンスが向上します

それほど重要ではありませんが、コードを読みにくくするスタイル上の問題がいくつかあります

  • 関数内の不要な空白の塊
  • COUNTRY_COUNT変数に大文字 (例: ) を使用することは一般的ではありません。多くの場合、すべての大文字は、lower または camelCase を使用した変数の定義用に非公式に予約されています。
于 2013-01-23T16:41:01.400 に答える
1
int mid = (int) r / 2;

本当に?中間点ではないことがわかると思います。また、他の場所で指摘されているように、値が見つからない場合の終了ケースはありません。無効なものを含め、さまざまな入力に対して再帰がどのように機能するかを考える必要があります。

私はそれを次のようにします:

int binary_search(Cdir directory[], char *key, int l, int r)
{
    int mid = (l+r) / 2;
    int c = strncmp(key, directory[mid].code, 3);

    if(c == 0) return mid;
    if(l>=r) return -1;

    if (c < 0)
        return binary_search(directory, key, l, mid - 1);

    return binary_search(directory, key, mid + 1, r);
}

これも:

char filename[] = "RandomStructDir.bin";

fd = open(filename, O_RDONLY, S_IRWXU);
if (fd < 0)
    perror(strcat(filename, " failed to open."));

filename[]スタック上の固定長配列です。エラーが発生したときに連結しようとします。それは未定義の動作であるため、より深刻なエラーを引き起こす可能性があります-スタックを破棄しています。

于 2013-01-23T16:53:31.873 に答える
0

スタック フレームが破損しています

スタックに対して大きすぎる変数を宣言したようです。それ以外の

int largeArray[1000][1000];

ポインタとして宣言する

int *largeArray[1000][1000];

もちろん、コードの変更は必要です。

于 2016-06-15T08:18:24.643 に答える
0

再帰関数では、一致する要素がない場合、終了ケースは表示されません。

于 2013-01-23T16:41:39.650 に答える