在什么情况下fscanf溢出内存?

时间:2014-01-30 02:45:58

标签: c linked-list

我有一个我实现的链表,适用于各种文件输入(它逐行读取并插入它们。)

void insert_words(FILE* file, node_type* list)
{
    char buffer[12];
    int length = 0;

    while (!feof(file)){
        fscanf(file, "%s", buffer);//buffer contains the string/name
        length = strlen(buffer);
        if (length != 0) { 
            insert_sorted(list, buffer);
        }
    } //while

}

鉴于此代码,我发现在读取'fff'之后使用给定的样本输入执行fscanf时出现的问题似乎很糟糕。

one
two

three ee
fff
ee

正在解析ee:

list = 0x009dfac0 {name=0x009dfac0 "one" next=0x00c98c08 {name=0x00c98c08 "three" next=0x00c98ba0 {name=0x00c98ba0 "two" ...} } }

下一个标记后:

list = 0x009dfac0 {name=0x009dfac0 "ee" next=0x009df068 {name=0x009df068 "È”ü\xf\x1" next=0x0ff7caa0 {msvcr110d.dll!_except_handler4(_EXCEPTION_RECORD *, _EXCEPTION_REGISTRATION_RECORD *, _CONTEXT *, void *)} {...} } 

检查我的列表时,fscanf被触发后,'next'指针立即被破坏。有什么可能的原因?

根据要求插入排序:

void insert_sorted(node_type* list, char* value)
{
    // Copy our pointer so we can move around
    node_type *n = (node_type*) malloc(sizeof *n); 
    node_type *loc = NULL;
    node_type *tmp;
    node_type dat;
    node_type* prev = list;
    node_type* head = list;

    n->next = NULL;
    strcpy(n->name, value); 

    // First element, assign immediately
    if( strcmp(list->name, "") == 0 )
    {
        *list = *n;
        return;
    }


    while(head != NULL)
    {
        // We should do a comparison to see if one is greater than another
        int cmp_result = strcmp(value, head->name);

        // If the value is bigger, this means the value needs to be inserted after
        if(cmp_result > 0)
        {           
            loc = head;
        }

        else if (cmp_result < 0) // this needs to be ahead
        {

            if(prev == head)    
            {
                dat = *head;
                *head = *n;
                head->next = &dat;
                return;
            }

            prev->next = n;
            n->next = head;
            return;
        }

        else if(cmp_result == 0)
        {
            free(n);
            return; // duplicate, die
        }


        // Advance to the next pointer
        prev = head;
        head = head->next;
    }


    // You've reached the end, that must mean you've succesfully reached the point to insert

    tmp = loc->next; // get the value we're going to end up detaching
    n->next = tmp; // link the two together
    loc->next = n;

}

2 个答案:

答案 0 :(得分:2)

将循环修改为

while (fscanf(file, "%s", buffer) == 1) {
    length = strlen(buffer);
    // ...
}

因为feof(file)在上次成功0后仍然返回fscanf()。在第一个失败后,它返回非0 fscanf()

关于insert_sorted(),请查看以下几行:

            head->next = &dat;
            return;

由于dat是本地对象,因此一旦函数返回,保存其地址会导致无效地址。

答案 1 :(得分:1)

您没有正确测试文件结尾。一般来说,使用feof是不正确的,而是测试从文件中读取的函数的返回值。

fscanf返回它能够读取的实体数量。因此,在您的情况下,您将测试它返回1,这表示成功读取。为避免缓冲区溢出,您可以使用%和s之间的数字限制要读取的字符数。

没有理由对你的缓冲区大小这么吝啬。

所以:

void insert_words(FILE* file, node_type* list)
{
    char buffer[128];

    while (fscanf(file, "%127s", buffer) == 1) {
        insert_sorted(list, buffer);
    }
}
顺便说一下,你不是“逐行”阅读,而是“用空格分隔的字符串以空格分隔的字符串”。要逐行阅读文件,您可以使用fgets。

在你说“那不是问题”之前,先试试吧。这是这个功能可能产生的唯一问题。