【问题标题】:Error Reading Variable, Cannot Access Memory at Address X读取变量时出错,无法访问地址 X 处的内存
【发布时间】:2013-01-23 16:37:11
【问题描述】:

可能只是 C 新手的另一个愚蠢的指针问题。不过想不出来这个。似乎我的堆栈帧以某种方式损坏了。该作业似乎几乎无关紧要,但它是一个相当基本的 I/O 练习。尝试通过单次读取读取结构数组(不能使用高级 I/O 函数,例如 fread())。

#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) { 

谢谢!

【问题讨论】:

标签: c


【解决方案1】:
int COUNTRY_COUNT = atoi(argv[1]);

读取国家的数量作为程序的参数,但您稍后在调用时硬编码假设这是&gt;= 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;
}

主要变化是

  • mid 的计算考虑了l 以及r
  • (如 Kirilenko 所述)认识到可能找不到匹配项。在这种情况下返回 -1
  • 减少对strcmp 的调用次数。非常小,但它使代码对我来说更清晰,并且会提高搜索性能

不太重要的是,有一些文体问题使您的代码难以阅读

  • 函数内部有大量不必要的空格
  • 对变量使用大写字母(例如COUNTRY_COUNT)是不常见的。所有大写通常非正式地保留给使用小写或驼峰式的变量定义

【讨论】:

  • 感谢您的所有建议。我确实应用了它们,尽管我仍然遇到与调用 binary_search 函数时相同的段错误,而不是在其中。
  • @user2004672 第一次调用binary_search 或在很长的调用链结束时是否会出现段错误?如果它发生在长链的末尾,则可能是堆栈溢出,这表明二分查找算法不正确。
  • 如果 lr 都应该是数组中的有效索引,那么 binary_search() 最初可能应该使用 COUNTRY_COUNT-1 作为更大的参数来调用。
  • 如果我可以提出更多修复建议,我会检查l &gt;= r 而不仅仅是==,因为如果找不到密钥,值可能会重叠。
  • @simonc 如果l=0r=1,那么mid将为0。如果不存在的键小于数组中的最小值,则再次向左搜索,使用r = mid - 1,即-1
【解决方案2】:
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[] 是堆栈上的固定长度数组。当发生错误时,您尝试连接到它。这可能只会导致更严重的错误,因为它是未定义的行为 - 您正在破坏堆栈。

【讨论】:

  • 谢谢,这个知识很有用。有趣的是,我的教授提供了这个错误处理的例子......
  • @user2004672 写perror(strcat(filename, " could not be accessed.")); 是白痴,教授还是没有教授。
【解决方案3】:

在你的递归函数中,如果没有匹配的元素,我看不到任何终止情况。

【讨论】:

    【解决方案4】:

    我的堆栈帧已损坏

    看起来很像您声明的变量对于堆栈来说太大了。而不是

    int largeArray[1000][1000];
    

    将其声明为指针

    int *largeArray[1000][1000];
    

    当然需要更改代码。

    【讨论】:

      猜你喜欢
      • 2019-03-26
      • 2016-03-07
      • 2023-03-12
      • 2017-08-28
      • 1970-01-01
      • 2018-09-08
      • 2013-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多