Код должен привести к ошибке сегментации, потому что из-за мелкого узла копирования в начале списка list1 удаляется, но заголовок list2 по-прежнему указывает туда - PullRequest
0 голосов
/ 11 октября 2019

Код должен приводить к ошибке сегментации из-за мелкого копирования, но вместо этого он позволяет печатать адрес головного узла для list2, когда printAll () вызывается для list2 в main (). Что нужно сделать, чтобы получить ожидаемое поведениеТакже, пожалуйста, объясните, почему это происходит? Я новичок. Заранее спасибо.

>>>> when tried with #pragma pack(1) it resuted in the first output

>>>> Without #pragma pack(1) it resulted in the second output



Here is the code i wrote.
The code is for creating an object (list1) of SLL class(singly linked list) and copying it to another object(list2) of SLL class.
#include <iostream>
using namespace std;

//#pragma pack(1)
class Node{
        public:
                char letter;
                Node *next;
};
class SLL{
        private:
                Node *head, *tail;
        public:
                SLL(){
                        head = NULL;
                        tail = NULL;
        }
        void printAll();// for printing the list
        void insertNewNode(char item);// for insertion at head                                
        //function for deletion at head
        void deleteAtHead(){ 
                   Node *tmp;
                   tmp = this->head;
                   this->head = this->head->next;
                   free(tmp);
        }
};
//it is for printing a singly linked list
void SLL::printAll(){

        Node *p;
        p = head;
        cout<<"VALUE  "<<"           "<<"  ADDRESS"<<endl;
        while(p!=NULL){
                cout <<p->letter << "--------------- "<<p<<endl;
                p = p->next;
        }
}
void SLL::insertNewNode(char item){
        Node* temp;
        temp = (Node *)malloc(sizeof(Node));
        temp->letter = item;
        temp->next = head;
        head = temp;
}
int main(){
        SLL list1;
        list1.insertNewNode('D');
        list1.insertNewNode('C');
        list1.insertNewNode('B');
        list1.insertNewNode('A');

        cout<<"PRINTING LIST1"<<endl;
        list1.printAll();
        cout<<""<<endl;

        cout<<"SHALLOW COPY INVOKED"<<endl;
        SLL list2 = list1;
        cout<<""<<endl;

        cout<<"PRINTING LIST2"<<endl;
        list2.printAll();

        list1.deleteAtHead();
        cout<<""<<endl;

        cout<<" LIST1 AFTER ITS HEAD DELETION"<<endl;
        list1.printAll();
        cout<<""<<endl;

        cout<<" LIST2"<<endl;
        list2.printAll();       // as soon as this is executed it should result in runtime error
        return 0;
}


>>>>>>> Output1:
PRINTING LIST1
VALUE               ADDRESS
 A ------------- 0x5578d6f872e0
 B ------------- 0x5578d6f872c0
 C ------------- 0x5578d6f872a0
 D ------------- 0x5578d6f87280

SHALLOW COPY INVOKED

PRINTING LIST2
VALUE               ADDRESS
 A ------------- 0x5578d6f872e0
 B ------------- 0x5578d6f872c0
 C ------------- 0x5578d6f872a0
 D ------------- 0x5578d6f87280

 LIST1 AFTER ITS HEAD DELETION
VALUE               ADDRESS 
 B  ------------- 0x5578d6f872c0
 C  ------------- 0x5578d6f872a0
 D  ------------- 0x5578d6f87280

 LIST2
VALUE               ADDRESS
  --------------- 0x5578d6f872e0

>>>>>> Output2:

PRINTING LIST1
VALUE               ADDRESS
 A ------------- 0x55baac1032e0
 B ------------- 0x55baac1032c0
 C ------------- 0x55baac1032a0
 D ------------- 0x55baac103280

SHALLOW COPY INVOKED

PRINTING LIST2
VALUE               ADDRESS
 A  ------------- 0x55baac1032e0
 B  ------------- 0x55baac1032c0
 C  ------------- 0x55baac1032a0
 D  ------------- 0x55baac103280

 LIST1 AFTER ITS HEAD DELETION
VALUE               ADDRESS
 B  ------------- 0x55baac1032c0
 C  ------------- 0x55baac1032a0
 D  ------------- 0x55baac103280

 LIST2
VALUE               ADDRESS
--------------- 0x55baac1032e0
B--------------- 0x55baac1032c0
C--------------- 0x55baac1032a0
D--------------- 0x55baac103280

1 Ответ

1 голос
/ 11 октября 2019

Указатели указывают на некоторую область памяти. Любая область памяти. Программы получают свою память из операционной системы, которая обычно выделяет ее большими кусками («страницами»), которые затем разделяет среда выполнения программы. Это делают подпрограммы, которые вызываются malloc, new и free, delete, а также механизмы вызова и возврата из подпрограмм.

Попытка использовать место в памяти, которое не было выделено программе, приводит кОшибка сегментации. Но использование памяти, выделенной для программы, не приводит к ошибкам.

Программы обычно не возвращают страницы, которые были им выделены. Вместо этого память просто используется повторно, например, для хранения различных переменных. Это оптимизация, поскольку операционная система требует больших усилий для выделения памяти. Это также уменьшает объем кэша, который использует программа.

Именно поэтому так называемый «висячий указатель» так опасен. Когда вы используете его, он возвращает данные. Только тщательная проверка покажет, что данные не имеют смысла. Он может даже возвращать правильные данные в течение длительного времени, пока область памяти не будет перезаписана и перезаписана чем-то другим. Тогда ваша программа вдруг показывает «неопределенное поведение» ...

...