-1

我有一个用 C 编写缓存模拟的项目,到目前为止,我一直在为数组和程序崩溃分配空间。请帮帮我。我必须在这个程序中使用指针。当我在主函数中简单地创建数组时,没有问题,但是在全局创建指针后,程序开始崩溃,我必须让它全局。它的要求之一。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <assert.h>

int INDEXLENGTH; // global variable for num of bits in index
int OFFSETLENGTH; // global variable for num of bits in byte offset
int TAGBITS; // global variable for num of bits in the tag
int misses=0; //variable for total number of misses
int hits=0;
int **tagAr; // LRUArray pointer
int **lruAr; // tagArray pointer
int cacheSize; // user specified size of cache
int blockSize; // user specified size of each block
int linesperset;
int sets;

int main(void)
{
    int i; // simply a few variables for future for loops
    int j;

    printf("Welcome to Lab A Cache Simulator by Divya, Alex and Jenn.\n");
    printf("To begin, please input the size of the cache you will be simulating in bytes.\n");
    scanf(" %d", &cacheSize); // (cache size in bytes) is read in from the user
    printf("You have inputed this: %d\n", cacheSize);

    printf("Next, please input the size of each cache line in bytes.\n");
    scanf(" %d", &blockSize); // blocksize is read in from the user
    printf("You have inputed this: %d\n", blockSize);

    printf("Finally, please input the number of ways of associativity for this cache.\n");
    printf("Also, input the number as a power of 2.\n");
    scanf(" %d", &linesperset); // linesperset is read in from the user
    printf("You have inputed this: %d\n", linesperset);

    sets = (cacheSize/(blockSize*linesperset));
    printf("Variable sets is: %d\n", sets);


    tagAr=(int **)malloc(sets*sizeof(int *)); // allocating space for "l" array pointers
    for (i=0; i<sets; i++) tagAr[i]=(int *)malloc(linesperset*sizeof(int)); //allocates space for k columns for each p[i]

    lruAr=(int **)malloc(sets*sizeof(int *)); // allocating space for "l" array pointers
    for (i=0; i<sets; i++) lruAr[i]=(int *)malloc(linesperset*sizeof(int)); //allocates space for k columns for each p[i]


    for (i=0; i<sets; i++)
        {
            for (j=0; j<blockSize; j++)
            {
                tagAr[i][j] = -1;
                lruAr[i][j] = -1;
            }
        }

    for (i = 0; i < sets; i++) //This part of the code prints array for debuging purposes
        {
            for (j = 0; j < blockSize; j++)
            {
                printf(" %d", lruAr[i][j]);
            }
            printf("\n");
            printf("\n");
        }

    printf("This is the value of IndexLength before setting, should be 0 : %d\n", INDEXLENGTH); //only for debuging purposes
    setIndexLength();
    printf("This is the value of IndexLength after setting: %d\n", INDEXLENGTH); //only for debuging purposes
    printf("This is the value of OffsetLength before setting, should be 0 : %d\n", OFFSETLENGTH); //only for debuging purposes
    offsetLength();
    printf("This is the value of OffsetLength after setting: %d\n", OFFSETLENGTH); //only for debuging purposes





    return misses;
}
4

2 回答 2

4

您有一个错字,在下面的代码中您设置tagAr[i]了两次并且从未设置过lruAr[i]

    tagAr=(int **)malloc(sets*sizeof(int *)); // allocating space for "l" array pointers
    for (i=0; i<sets; i++) tagAr[i]=(int *)malloc(linesperset*sizeof(int)); //allocates space for k columns for each p[i]

    lruAr=(int **)malloc(sets*sizeof(int *)); // allocating space for "l" array pointers
    for (i=0; i<sets; i++) tagAr[i]=(int *)malloc(linesperset*sizeof(int)); //allocates space for k columns for each p[i]

第二个tagAr[i]任务应该是 to lruAr[i]

所以,这就是你想要的:

    tagAr=malloc(sets*sizeof(int *)); // allocating space for "l" array pointers
    for (i=0; i<sets; i++) tagAr[i]=malloc(linesperset*sizeof(int)); //allocates space for k columns for each p[i]

    lruAr=malloc(sets*sizeof(int *)); // allocating space for "l" array pointers
    for (i=0; i<sets; i++) lruAr[i]=malloc(linesperset*sizeof(int)); //allocates space for k columns for each p[i]
于 2013-10-01T16:15:30.853 回答
2

这并不是真正的答案,而是 Pankrates 非常好的建议的后续行动。

如果你在下面运行程序valgrind(为了安全起见,在用调试信息编译它并且没有优化之后)

$ gcc -O0 -g -o test.o -W -Wall test.c   # Compile

$ valgrind ./test.o     # run simple Valgrind

你得到:

==26726== Use of uninitialised value of size 8
==26726==    at 0x4008C5: main (test.c:54)
==26726==
==26726== Invalid write of size 4
==26726==    at 0x4008C5: main (test.c:54)
==26726==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==26726==
==26726==

它告诉您在源文件的第 54 行,您正在写入一个未初始化的变量。你没有分配的东西。Valgrind 告诉你什么和在哪里。要发现原因,该行是:

lruAr[i][j] = -1;

所以你检查你分配lruAr的位置(valgrind 说它没有分配!),你很快就会发现什么看起来像一个复制粘贴错误:

对于 (i=0; i)malloc(linespersetsizeof(int)); //为每个p[i]分配k列空间

tagAr=(int **)malloc(sets*sizeof(int *));
for (i=0; i<sets; i++) {
    tagAr[i]=(int *)malloc(linesperset*sizeof(int)); // <-- ORIGINAL LINE
}

lruAr=(int **)malloc(sets*sizeof(int *));
for (i=0; i<sets; i++) {
    tagAr[i]=(int *)malloc(linesperset*sizeof(int)); // <-- THE COPY ("tagAr"?)
}

修复方法是 Charlie Burns 所描述的。

Valgrind可以帮助您做的远不止这些,并且会帮助您拦截更微妙的错误——这些错误不会导致您的应用程序立即崩溃并且可重现

出于同样的原因,不要使用强制转换(或仅作为最后的手段)。通过强制转换,您是在告诉编译器“我知道得更好”。事实是,编译器通常比您和我以及大多数其他人都知道得更多。通过不使用演员表,当你无意中做了一些可疑的事情时,你让它站起来说话,而不是默默地继续做你告诉它做的事情,而不是你想让它做的事情。

(对不起,长篇大论和傲慢的咆哮。但我被咬了很多次,我想也许我可以救你一些皮肤:-))

更新

“仍然崩溃”。好的,所以我们valgrind在更新源后再次运行,这次我们得到

==28686== Invalid write of size 4
==28686==    at 0x4008B8: main (test.c:54)
==28686==  Address 0x51e00a0 is 0 bytes after a block of size 16 alloc'd
==28686==    at 0x4C2C27B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==28686==    by 0x4007F3: main (test.c:43)
==28686==
==28686== Invalid write of size 4
==28686==    at 0x4008E2: main (test.c:55)
==28686==  Address 0x51e0190 is 0 bytes after a block of size 16 alloc'd
==28686==    at 0x4C2C27B: malloc (in /usr/lib64/valgrind/vgpreload_memcheck-amd64-linux.so)
==28686==    by 0x400852: main (test.c:46)

注意:我们在 block 之后写入 0 个字节。这意味着我们有一个缓冲区溢出:我们确实分配了一个数组,但它太小了。或者我们的写太大了。

该数组在第 43 行和第 46 行(两个循环的 malloc)分配,并写在这里:

            tagAr[i][j] = -1;
            lruAr[i][j] = -1;

...所以这意味着它tagAr[i]有一个宽度,但blockSize更大。

这可能是由于我插入了无意义的数据,所以您必须检查自己。但很明显,您分配linesperset元素并写入blockSize它们。最起码,blockSize绝对不允许超过linesperset

最后

下面的代码通过了valgrind测试。我还添加了内存确实已分配的检查它几乎总是不必要的,没有它,程序几乎永远不会崩溃和核心转储。如果几乎从来没有也不应该你不够好,你最好检查一下。

// allocating space for "l" array pointers
tagAr=malloc(sets*sizeof(int *));
lruAr=malloc(sets*sizeof(int *));

if ((NULL == tagAr)||(NULL == lruAr)) {
    fprintf(stderr, "out of memory\n");
}

for (i=0; i < sets; i++) {
    tagAr[i] = malloc(linesperset*sizeof(int));
    lruAr[i] = malloc(linesperset*sizeof(int));
    for (j=0; j < linesperset; j++) {
         tagAr[i][j] =
         lruAr[i][j] = -1;
    }
}

出于同样的原因,即使许多人称它为偏执和顽固,现代垃圾收集语言也嘲笑它,一旦完成释放每个分配的指针并将其设置为 NULL 是一个好习惯(不是为了防止闲逛——而是为了确保您没有在某处使用过时的值)。

// To free:
for (i=sets; i > 0; ) {
    i--;
    // To be really sure, you might want to bzero()
    // lruAr[i] and tagAr[i], or better still, memset()
    // them to an invalid and easily recognizable value.
    // I usually use 0xDEADBEEF, 0xDEAD or 0xA9.
    free(lruAr[i]); lruAr[i] = NULL;
    free(tagAr[i]); tagAr[i] = NULL;
}
free(lruAr); lruAr = NULL;
free(tagAr); tagAr = NULL;

(上述做法,包括 0xA9 值,来自Writing Solid Code)。

于 2013-10-01T16:41:22.777 回答