0

I was trying to implement insert, delete and linear search in an string type array in the same code. Delete and Linear search works fine here, but insertion is not running perfectly.

Here is the main function of my code.

#include<iostream>
#include <stdlib.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>    
int main(int argc, char ** argv)
    {
        int siz;
        cout<<"How many elements:";
        cin>>siz;
        string student[siz];
    
        for(int i=0; i<siz; i++)
        {
            cin>>student[i];
        }
        cout<<"Array:";
        for(int i=0; i<siz; i++)
            cout<<student[i]<<endl;
    
        int choice;
        cout <<"Enter your choice :";
        cin>>choice;
    
        switch(choice)
        {
        case 0:
            exit(0);
            break;
        case 1:
            st_insert(student,siz);
            break;
        case 2:
            st_delete(student,siz);
            break;
        case 3:
            st_search(student,siz);
            break;
        case 4:
            cout<<"All elements\n:";
            for(int i=0; i<siz; i++)
                cout<<student[i]<<endl;
            break;
        default:
            cout<<"Wrong choice please try again !!!";
        }
    
        return 0;
    }

The insert function is

void st_insert(string demo[], int siz)
{

    int pos;
    cout<<"Enter a position number to insert:";
    cin>>pos;
    string item;
    cout<<"Enter a new Element :";
    cin>>item;
    cout<<"After Inserting "<<item<<", the updated list is: "<<endl;
    for (int i=siz-1; i>=pos; i--)
    {
        demo[i+1] = demo[i];
    }
    demo[pos] = item;
    for (int i=0; i<siz+1; i++)
        cout<<"\t"<<demo[i]<<endl;
}

Sample Output if I want to insert an item

Insert_Output

Apprentice
  • 65
  • 3
  • 1
    why you are implementing this from scratch, instead use the library function – Sachin Kumar Aug 31 '20 at 03:30
  • 1
    `string student[siz];` is not C++ -- it is a non-standard VLA provided as a non-standard extension by some compilers. `for (int i=siz-1; i>=pos; i--)` with `demo[i+1]` invokes Undefined Behavior as `demo[siz]` is one past the end of `demo`. (additionally, you cannot use any user-input function correctly unless you check the stream-state before making use of the result) – David C. Rankin Aug 31 '20 at 03:30
  • @SachinKumar, I was just trying to implement the theoretical aspect of inserting as a beginner. – Apprentice Aug 31 '20 at 03:32
  • @DavidC.Rankin, Is there any solution to fix this up? – Apprentice Aug 31 '20 at 03:33
  • [Variable Lenth Array](https://stackoverflow.com/questions/1887097/why-arent-variable-length-arrays-part-of-the-c-standard) is not allowed in C++ standard but might be allowed as an extension in some compilers. My suggestion: use `std::vector` instead. Because dynamical insertion requires dynamical memory allocation. While the size of `string student[siz]` is fixed by `siz`. – Louis Go Aug 31 '20 at 03:36

3 Answers3

1

Yes, there is a solution. Don't use non-standard VLAs and don't use Plain-Old Arrays that provide no bounds checking. The solution is to use a vector of strings, e.g. std::vector<std::string>. That way you can add or replace any element you like and the memory is handled automatically.

For example, let's just take a vector of strings initialized with four strings:

    std::vector<std::string> student { "my", "dog", "has", "fleas" };

Now student.size() will tell you how many strings are contained in the vector and you can replace (with bounds checking) with student.at(pos) = "new string";

You can list all elements in your vector using a range-based for loop, e.g.

    std::cout << "Array:\n\n";
    for (const auto& s : student)
        std::cout << s << '\n';

Since the vector of strings student contains all the information you will need to either replace an existing element or add a new element at the end, your function (which must be of a type to indicate success/failure of the operation) could be written to take a single parameter -- a reference to your vector of strings, e.g.:

bool st_insert(std::vector<std::string>& demo)
{

    size_t pos;
    std::string item {};
    std::cout << "Enter a position number to insert: ";
    if (!(std::cin >> pos))
        return false;
    
    std::cout << "Enter a new Element: ";
    if (!(std::cin >> item))
        return false;
    
    if (pos >= demo.size())
        demo.push_back(item);
    else
        demo.at(pos) = item;
    
    std::cout << "\nAfter Inserting \""<< item <<"\", the updated list is:\n\n";
    for (const auto& s : demo)
        std::cout << s << '\n';
    
    return true;
}

If you want a compilable example, with 0-exit or 1-st_insert as your menu choices, you could do:

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>

bool st_insert(std::vector<std::string>& demo)
{

    size_t pos;
    std::string item {};
    std::cout << "Enter a position number to insert: ";
    if (!(std::cin >> pos))
        return false;
    
    std::cout << "Enter a new Element: ";
    if (!(std::cin >> item))
        return false;
    
    if (pos >= demo.size())
        demo.push_back(item);
    else
        demo.at(pos) = item;
    
    std::cout << "\nAfter Inserting \""<< item <<"\", the updated list is:\n\n";
    for (const auto& s : demo)
        std::cout << s << '\n';
    
    return true;
}

int main (void)
{
    int choice;
    std::string tmp;
    std::vector<std::string> student { "my", "dog", "has", "fleas" };
    
    std::cout << "Array:\n\n";
    for (const auto& s : student)
        std::cout << s << '\n';

    std:: cout << "\nEnter menu choice: ";
    if (!(std::cin >> choice)) {
        std::cerr << "error: invalid integer value - choice.\n";
        return 1;
    }

    switch(choice)
    {
    case 0:
        exit(0);
        break;
    case 1:
        if (!st_insert (student))
            std::cerr << "error: unable to insert element.\n";
        break;
    default:
        std::cout << "Wrong choice please try again !!!\n";
    }

    return 0;
}

Example Use/Output

Replace Exmaple:

$ ./bin/insert_str_item
Array:

my
dog
has
fleas

Enter menu choice: 1
Enter a position number to insert: 1
Enter a new Element: cat

After Inserting "cat", the updated list is:

my
cat
has
fleas

Add Example:

$ ./bin/insert_str_item
Array:

my
dog
has
fleas

Enter menu choice: 1
Enter a position number to insert: 40
Enter a new Element: now

After Inserting "now", the updated list is:

my
dog
has
fleas
now

(note: the st_insert() function was written so if the requested pos for the new string exceeds what the next string in the vector would be, it is simply added as the next string and the invalid position is discarded)

Now when you go to take input for your vector of strings, it is quite simple. just read your input into a temporary string and use the .push_back() member function to add the string to your vector of strings, e.g.

std::string tmp {};
std::cout << "enter a string: ";
if (std::cin >> tmp)
    student.push_back(tmp);

(note: you must validate every user input before you use the value)

Adding Taking siz New Elements

From your example, if you did want to specify the number of new strings to enter, you could adjust the program as follows:

int main (void)
{
    int choice;
    size_t siz;
    std::string tmp;
    std::vector<std::string> student { "my", "dog", "has", "fleas" };
    
    std::cout << "There are currently " << student.size() << " elements:\n\n";
    for (const auto& s : student)
        std::cout << s << '\n';
    
    std::cout << "\nHow many elements would you like to add? ";
    if (!(std::cin >> siz)) {
        std::cerr << "error: invalid size-type input.\n";
        return 1;
    }
    
    for (size_t i = 0; i < siz; i++) {
        std::cout << "student[" << student.size() << "]: ";
        if (std::cin >> tmp)
            student.push_back(tmp);
    }
    
    std::cout << "\nCurrent strings:\n\n";
    for (const auto& s : student)
        std::cout << s << '\n';
    
    std:: cout << "\nEnter menu choice: ";
    if (!(std::cin >> choice)) {
        std::cerr << "error: invalid integer value - choice.\n";
        return 1;
    }

    switch(choice)
    {
    case 0:
        exit(0);
        break;
    case 1:
        if (!st_insert (student))
            std::cerr << "error: unable to insert element.\n";
        break;
    default:
        std::cout << "Wrong choice please try again !!!\n";
    }

    return 0;
}

Example Use/Output

$ ./bin/insert_str_item
There are currently 4 elements:

my
dog
has
fleas

How many elements would you like to add? 4
student[4]: my
student[5]: cat
student[6]: has
student[7]: none

Current strings:

my
dog
has
fleas
my
cat
has
none

Enter menu choice: 1
Enter a position number to insert: 5
Enter a new Element: frog

After Inserting "frog", the updated list is:

my
dog
has
fleas
my
frog
has
none

You will want to see std::vector and std::basic::string for full details of the use of std::vector and std::string. Also see: Why is “using namespace std;” considered bad practice? and C++: “std::endl” vs “\n”.

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

In C++, arrays have a fixed sized and when passed as parameters what you are actually getting is a pointer to the first element in the array. In you code, you are trying to access demo[i+1] when size equals size-1; this generates an error because you are trying to access a memory location that isn't part of the array (demo[size]). When inserting an element in an array, you need to first allocate a new chunk of memory with the new size, then you copy each element over(including the new value), and finally delete the old chunk of memory which is now unused.

emegona
  • 168
  • 1
  • 12
0

As rightly said by some authors , what is required by you should not be done by fixed memory allocation , instead dynamic memory allocation (example : vectors in c++) should be used. However since you wanted to try the fixed one still, you can do the following :

  1. Declare a string array of a larger size, instead of the user input (siz). Let's say it to be of predefined size 1000. (You can notify user to have a array of size to be less).
  2. Declare the siz variable as global and not local. Because when you come after doing any insertion / deletion operation your size should be more / less than it previously was.But if you are using it as local then the changes would not be reflected because of call by value.

EDITED code:

#include<iostream>
#include <stdlib.h>
#include<stdio.h>
#include<algorithm>
#include<string.h> 
using namespace std;

int siz=0;

void st_insert(string demo[])
{

    int pos;
    cout<<"Enter a position number to insert:";
    cin>>pos;
    string item;
    cout<<"Enter a new Element :";
    cin>>item;
    cout<<"After Inserting "<<item<<", the updated list is: "<<endl;
    for (int i=siz-1; i>=pos; i--)
    {
        demo[i+1] = demo[i];
    }
    demo[pos] = item;
    siz++;
    for (int i=0; i<siz; i++)
        cout<<"\t"<<demo[i]<<endl;
}

int main(int argc, char ** argv)
    {
        cout<<"How many elements:";
        cin>>siz;
        string student[1005];
    
        for(int i=0; i<siz; i++)
        {
            cin>>student[i];
        }
        cout<<"Array:";
        for(int i=0; i<siz; i++)
            cout<<student[i]<<endl;
    
        int choice;
        cout <<"Enter your choice :";
        cin>>choice;
    
        switch(choice)
        {
        case 0:
            exit(0);
            break;
        case 1:
            st_insert(student);
            break;
        case 4:
            cout<<"All elements\n:";
            for(int i=0; i<siz; i++)
                cout<<student[i]<<endl;
            break;
        default:
            cout<<"Wrong choice please try again !!!";
        }
    
        return 0;
    }

Rest all seems fine to me. Hope you got it. :)

KL_KISNE_DEKHA_HAI
  • 649
  • 11
  • 26
  • And the second method is as stated by@mgonnav , that each time you need to allocate memory of increased size , copy all from old to new including the new element , and delete the earlier used array. – KL_KISNE_DEKHA_HAI Aug 31 '20 at 04:14