rahul singhania
rahul singhania

Reputation: 237

Why am i getting segmentation fault in this function?

I have tried all possible ways. I think there is some logical error in the function findlink()
The purpose of this function is to find and return a pattern from the argument abc.
For example, if abc is "Hello,My name is **Lorem ipsum sit amet ** and I am a student.", then findlink will return "Lorem ipsum sit amet". i.e. it returns the text between double asterisk. But due to some reason I am getting segmentation fault, though I have debugged and figured out that the fault is concerned with this function only, but I am unable to discover why.

char *findlink(char *abc)
{
    if(abc==NULL)
        return NULL;
    cout<<"Findlink called for : "<<abc<<endl;
    int i=0,flag=0,flag1=0,len=0;
    char *link;
    for(i=0;i<strlen(abc)-1;i++)
    {
        if(abc[i]=='*' && abc[i+1]=='*' && flag==0)
        {
            flag=1;
            i+=2;
        }
        if(abc[i]=='*' && abc[i+1]=='*' && flag==1)
        {
            flag=0;
            flag1=1;
            i+=2;
        }
        if(flag==1 && flag1!=1)
            link[len++]=abc[i];
        if(flag1==1)
        {
            link[len++]='\0';
            cout<<"Returning "<<link<<endl;
            return link;
        }
    }
    cout<<"Returning NULL\n";
    return NULL;
}

.
Following is the full code for reference.

#include<iostream>
#include<fstream>
#include<string.h>
#include<stdio.h>
using namespace std;
ifstream infile;
ofstream outfile;
struct queue
{
    struct node *front;
    struct node *rear;
};
struct queue* createqueue()
{
    struct queue *temp=new queue;
    temp->front=NULL;
    temp->rear=NULL;
    return temp;
}
struct node
{
    struct node *next;
    char *value;
};
struct node * createnode(char *val)
{
    struct node *new1=new node;
    new1->next=NULL;
    new1->value=val;
    return new1;
}
struct queue *push(char *val,struct queue *queue1)
{
    struct node *new1=createnode(val);
    if(queue1->front==NULL && queue1->rear==NULL)
    {
        queue1->front=queue1->rear=new node;
        queue1->rear=new1;
        queue1->front=new1;
    }
    else
    {
        queue1->rear->next=new node;
        queue1->rear->next=new1;
        queue1->rear=queue1->rear->next;
    }
    return queue1;
}
struct queue *push(string val,struct queue *queue1) //overloaded function push for string arguments
{
    char* cstr = new char[val.length() +1]; 
    strcpy(cstr, val.c_str()); 
    queue1=push(cstr,queue1);
    return queue1;
};
struct queue *pop(struct queue *queue1)
{
    struct node *temp=new node;
    if(queue1->front==NULL)
        return NULL;
    else if(queue1->front==queue1->rear)
    {
        temp=queue1->front;
        queue1->front=NULL;
        queue1->rear=NULL;
        cout<<"POP: Poping: "<<temp->value<<endl;
        return queue1;
    }
    else
    {
        temp=queue1->front;
        queue1->front=queue1->front->next;
        cout<<"POP: Poping: "<<temp->value<<endl;
        return queue1;
    }
}
struct queue *scanitall(struct queue *queue1)       //reads the contents from outputproject.txt and pushes all the contents in a queue
{
    string line;
    infile.open("outputproject.txt");
    while(getline(infile,line))
    {                    
        char *line1=new char[line.length()+1];
        strcpy(line1,line.c_str());
        queue1=push(line1,queue1);
    }
    infile.close();
    return queue1;
}
int search(struct queue* queue1,char *val)  //returns 1 if val found in queue1 else 0
{
    //cout<<"SEARCH called\n";
    if(queue1->front==NULL || queue1->rear==NULL)
        return 0;
    struct node *temp=new node;
    temp=queue1->front;
    while(temp)
    {
        if(strcmp(temp->value,val)==0)
            return 1;
        temp=temp->next;
    }
    return 0;
}
char *findlink(char *abc)
{
    if(abc==NULL)
        return NULL;
    cout<<"Findlink called for : "<<abc<<endl;
    int i=0,flag=0,flag1=0,len=0;
    char *link;
    for(i=0;i<strlen(abc)-1;i++)
    {
        if(abc[i]=='*' && abc[i+1]=='*' && flag==0)
        {
            flag=1;
            i+=2;
        }
        if(abc[i]=='*' && abc[i+1]=='*' && flag==1)
        {
            flag=0;
            flag1=1;
            i+=2;
        }
        if(flag==1 && flag1!=1)
            link[len++]=abc[i];
        if(flag1==1)
        {
            link[len++]='\0';
            cout<<"Returning "<<link<<endl;
            return link;
        }
    }
    cout<<"Returning NULL\n";
    return NULL;
}
struct queue *processit(struct queue *queue1,char *abc) //identifies link text in inputproject.txt
{
    //cout<<"PROCESSIT called\n";
    ofstream outfile;
    outfile.open("outputproject.txt",ios::app);
    if(!outfile)
        cout<<"PROCESSIT: Error file not opened!\n";
    char *link;
    link=findlink(abc);
    if(link)
        cout<<"Caught: "<<link<<endl;
    if(link)
        if(search(queue1,link)==0)
            {
                cout<<"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n";
                outfile<<link<<endl;
                queue1=push(link,queue1);
            }
    outfile.close();
    return queue1;
}
void openallfiles(struct queue *queue1)
{
    if(!queue1->rear)
        cout<<"Queue Empty\n";
    else
    {
        struct node *temp=new node;
        temp=queue1->front;
        string line;
        while(temp)
        {
            ifstream infile;
            infile.open(temp->value);
            if(!infile)
            {
                cout<<"openallfiles:File not opened\n";
                return;
            }
            while(getline(infile,line))
            {
                cout<<line<<endl;
            }
            infile.close();
            if(temp)
                temp=temp->next;
        }
    }
}/*
struct queue *findlinks(struct queue *crawl1,ifstream infile)
{

}
crawl(struct queue *crawl1)
{
    ifstream infile1,infile2;
    infile1.open("inputproject.txt");
    crawl1=findlinks(crawl1,infile1);
}*/
void display(struct queue *queue1)
{
    if(queue1->front)
    {
        struct node *temp=queue1->front;
        while(temp)
        {
            cout<<"data:"<<temp->value<<endl;
            temp=temp->next;
        }
    }
    else{
        cout<<"Sorry queue empty\n";
    }
}
int main()
{
    struct queue *queue1=createqueue();
    struct queue *crawl1=createqueue();
    queue1=scanitall(queue1);       //push all contents of outputproject.txt in  a queue
    display(queue1);
    //cout<<"Poping:\n";
    /*while(queue1->rear)
        queue1=pop(queue1);*/
    string line;
    char *line1;
    infile.open("inputproject.txt");
    while(getline(infile,line))
    {
        line1=new char[line.length()+1];
        strcpy(line1,line.c_str());
        queue1=processit(queue1,line1);
    }
    infile.close();
    openallfiles(queue1);
    return 0;
}

Upvotes: 0

Views: 68

Answers (2)

The problem is that struct node holds a pointer to char. If you trace down all the calls nothing allocates a copy of line1, so all the nodes end up pointing at the same buffer. (Technically, it is undefined behaviour because line1 ceases to exist each time round the while loop, in practise though, they will all point to the same place on the stack.)

The fix is to make struct node hold a std::string, and then instead of calling strncpy, you can just push the string.

Upvotes: 0

Khalil Khalaf
Khalil Khalaf

Reputation: 9407

The string class has a constructor that takes a NULL-terminated C-string. No use of strncpy() in your case. To convert from a C-String to a string you do it directly. Example:

char MyCharArray[] = "Whatever";

std::string MyStandardString(MyCharArray); // done

On the other hand, to convert a string to a C-String you can use the built in function of the class string which is the apply of the D3 rule:

char YourCharArray = YourString.c_str();

But that is considered bad practice, why? Because when your string "dies", so your char array.

You, instead, need to use something like this:

std::string YourString = "hello world";
char* YourCharArray = new char[YourString.length() + 1]; // notice the "new", means your pointer "allocated" new memory just for itself

std::strcpy(YourCharArray, YourString.c_str());
delete[] YourCharArray; // this and only this will kill your CharArray. Which you "HAVE" to in order to "free" the memory once your program ends executing 

Look here for Documentation on C-String to string and Here for string to C-String

Advice: Don't practice the use of using namespace std; Why? Look here: Why is “using namespace std” in C++ considered bad practice?.

Upvotes: 2

Related Questions