【问题标题】:Pointer logic causing an access violation导致访问冲突的指针逻辑
【发布时间】:2013-04-23 18:28:46
【问题描述】:

我添加联系人的程序方法之一是在执行时出现以下错误:

Unhandled exception at 0x00111deb in G00290342.exe: 0xC0000005: Access violation reading location 0x00000050.

我研究了这个错误,发现它是由访问已在使用的内存引起的。我已将其缩小到导致“curr”变量为 NULL 的 readFile 方法中的指针逻辑。

它正在中断的代码在这里:

while(curr->next != NULL)
    {
        curr = curr->next;

    }

这是完整的方法供参考:

int addContact(struct contact *theList)
{
    struct contact *newContact, *curr;
    char fn[15],sn[15],ph[15],cmpy[15],eml[15];

    //create the new structure
    newContact = (struct contact *)malloc(sizeof(struct contact));
    if(newContact == NULL)
    {

        return(0);

    }
    //find the end of list
    curr = theList;
    //scroll through the list
    while(curr->next != NULL)
    {
        curr = curr->next;

    }
    //now have the last contact and the new one here
    printf("\nEnter a surname: ");
    gets(newContact->sname);

    printf("\nEnter a first name: ");
    gets(newContact->fname);

    printf("\nEnter a phone: ");
    gets(newContact->phone);

    printf("\nEnter a company: ");
    gets(newContact->company);

    printf("\nEnter an email: ");
    gets(newContact->email);

    //add the new contact to the end of the list

    curr->next = newContact;
    newContact->prev = curr;
    newContact->next = NULL;
    return(0);


}//end addContact

这是我读取测试文件的主要方法:

main()
{
    int sts,iChoice;
    struct contact *ptrList, *head;

    //head of sorted list
    struct contact *srtdList;

    srtdList = NULL;
    ptrList = NULL;

    ptrList = readFile("test.csv",ptrList);
    head = ptrList;

    /////menu for options
    system("cls");
    printf("\n\n\t\tWelcome to BV Contact Organizer\n\n");
    printf("\n\n\t\tEnter a number ranging from 1 to 6 for options.\n\n");
    printf("\n\t\t1. Search");
    printf("\n\t\t2. Add");
    printf("\n\t\t3. Sort");
    printf("\n\t\t4. Remove");
    printf("\n\t\t5. Edit");
    printf("\n\t\t6. Exit");
    printf("\n\n\t\tEnter your menu choice: ");
    fflush(stdin);
    scanf("%d", &iChoice);

    // user enters one of 6 values:
    // Search,add,sort,remove,exit or edit contacts


    switch(iChoice)
    {

        case 1:     // Add
        {
            sts = addContact(head);
            sts = writeListToFile("test.csv",head);
            while(ptrList != NULL)
            {
                printf("\n%s,%s,%s,%s,%s",ptrList->sname,ptrList->fname,ptrList->phone,ptrList->company,ptrList->email);
                ptrList = ptrList->next;

            }

            break;
        }
        case 2:     // Sort
        {
            //return the head of the sorted list to here
            srtdList = sortList(head,srtdList);
            head = srtdList;
            if(srtdList != NULL)
            {

                printf("\n\nSorted List");
                while(srtdList != NULL)
                {
                    printf("\n%s,%s,%s,%s,%s",srtdList->sname,srtdList->fname,srtdList->phone,srtdList->company,srtdList->email);
                    srtdList = srtdList->next;

                }

                sts = writeListToFile("testSort.csv",head);

            }
            else
            {
                printf("nothing to print");

            }
            printf("\n\n\n");
            system("pause");
            break;
        }
        case 3:     // Exit
        {
            printf("\n\nProgram exiting!...");
            break;
        }
        default:
        {
            printf("\n\nInvalid menu choice,please choose a number ranging from 1 to 6!...");
        }

    }//end of switch


    return(iChoice);

} // end of main

这是所要求的结构联系定义:

struct contact {
        char sname[15];
        char fname[15];
        char phone[15];
        char company[15];
        char email[15];
        struct contact *prev;
        struct contact *next;
};

这是用于读取文件的方法并导致问题:

struct contact *readFile(char * FName,struct contact *ptrList)
{

struct contact *head, *newContact;
FILE *fptr;
char oneLine[60];
char *sname, *fname, *phone,*company, *email;

head = ptrList;

fptr = fopen(FName,"r");

if(fptr == NULL)
{
    printf("\nCant open file!");
    return(ptrList);

}

fgets(oneLine, 55, fptr);
while(!feof(fptr))
{
    fgets(oneLine, 55, fptr);
    if(oneLine[strlen(oneLine)-1] == '\n')
    {
        oneLine[strlen(oneLine)-1] = '\0';

    }

    sname = strtok(oneLine,",");
    fname = strtok(NULL,",");
    phone = strtok(NULL,",");
    company = strtok(NULL,",");
    email = strtok(NULL,",");

    if(head == NULL)
    {
        head = (struct contact *)malloc(sizeof(struct contact));
        ptrList = head;
        strcpy(head->sname,sname);
        strcpy(head->fname,fname);
        strcpy(head->phone,phone);
        strcpy(head->company,company);
        strcpy(head->email, email);

        head->prev = NULL;
        head->next = NULL;


    }
    else
    {

        newContact = (struct contact *)malloc(sizeof(struct contact));
        head->next = newContact;
        newContact->prev = head;
        newContact->next = NULL;
        //copy the data to the new one
        strcpy(head->sname,sname);
        strcpy(head->fname,fname);
        strcpy(head->phone,phone);
        strcpy(head->company,company);
        strcpy(head->email,email);

        //move down the list so that the head variable
        //points to the last contact
        head = newContact;

    }

  }//end while

  fclose(fptr);
  return(ptrList);
}

【问题讨论】:

  • 您确定curr 不是NULL,因为它看起来就是这样。看起来与NULL 这里的0x00000050有些偏移
  • 您没有检查“theList”是否为 NULL。如果是这样,您的 while 循环将失败。至少断言它。
  • 您可能想在尝试遍历之前检查theList 是否为NULL,因为如果是,您新分配的节点应该成为新的列表头。此外,由于报告的值不是0x00000000,很可能您一开始就没有正确地将列表头初始化为NULL,这是逻辑上的另一个错误。最后,您需要通过地址(即双指针)传入列表头,或者始终将真实的列表头作为函数结果返回,否则您将永远无法正确设置外部列表头。
  • 而且.. 好像这还不够,不要使用gets()。该功能在安全方面非常糟糕,它已从语言中弃用,并且不会包含在下一个标准中。请改用fgets()。由于您正在更新您的问题帖子,您是否有机会也可以添加 struct contact 的结构定义?
  • @WhozCraig 我认为是0x00000050,因为这是nextcontact 对象中的偏移量。

标签: c pointers memory-management data-structures


【解决方案1】:

所以你将curr 分配给theList 没有任何NULL 检查:

curr = theList;

所以当您到达while 时,如果curr 确实是NULL,那么当您尝试执行curr->next 时,您将遇到访问冲突:

while(curr->next != NULL)
{
    curr = curr->next;
}

【讨论】:

  • 那是我的回答 :) - 虽然 +1 你的更漂亮
  • 是的,我刚刚在 curr = theList; 上添加了一个空检查。它给了我错误'curr'正在使用而没有被初始化。我的第二个问题是我该如何解决这个问题?
  • @user2307951 很难说,但我的猜测是在readFile 中您无法打开文件并且您返回ptrList 这是NULLaddContact 应该有逻辑如果没有初始化 head,则可以创建 head,因为 WhozCraig 说您需要将 theList 作为双指针传递才能工作。
  • 阅读readFile(),当您将现有列表传递给函数时会发生什么? head 最初将设置为 ptrList,它可能有一个 next 指向列表的其余部分。然后,在第一个读取的节点上,head->next = newContact 孤立了最初的ptrList 节点之后的所有内容,从而丢失(并泄漏)这些节点。您可能也想解决这个问题,或者不要费心让该函数修改现有列表,只需取出 ptrList。正如目前所写的那样,它无论如何都不起作用。
  • 我不确定我将如何实现它?所以它源于我的“readFile”方法。如果我取出“ptrList”我会怎么做?
【解决方案2】:

上面写着Access violation reading location 0x00000050 所以你正试图读取一个实际上是一些垃圾值的内存位置。从头开始跟踪 theList 值,此外,无论您在何处分配内存,请立即执行memset(newContact,0,sizeof(struct contact))。说了这么多,如果还是遇到问题,提供代码,可能逻辑有问题

【讨论】:

  • 我尝试了 memset sn-p 但我收到一个错误,提示类型为 contact 的参数与类型 int 不兼容。我已经用上面我正在阅读的主要方法更新了我的问题列表。
  • 对不起,memset 中的错字:)
  • 我在mem分配后又添加了memset sn-p,这个sn-p到底是做什么的?
  • 如果您添加空检查,您确保可以正确检测到空列表或列表末尾。在方法的最后,您添加了newContact->next = NULL;,这使得这成为可能。现在 memset 会将 malloc 分配的整个内存设置为 0。因此,即使您错过了它或其他地方可能仍然错过了它,memset 已经对此进行了补偿,并且您的 null 检查仍然有效。基本上这是一种故障安全机制。
  • 酷我刚刚在那里测试过它说'curr'没有初始化。我该如何解决这个问题?
【解决方案3】:
curr = theList;    
 while(curr->next != NULL)
 {
    curr = curr->next;

}

如果theList 中的最后一个元素是not null 并指向垃圾内存位置,也可能会发生此问题

【讨论】:

  • 好的,我解决了这个问题,结果证明这是我的 readFile 方法,因为指针没有正确初始化。你能发现我的指针在哪里搞砸了吗?
  • 以上代码存在多个问题。 1. 在readFileelse block 中,您应该将名称电话公司等的新值分配给newContact 而不是head。 2. 在返回之前,你永远不会给ptrList 分配任何东西。所以method 总是返回null。这会导致内存问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-11
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多