I have a code where I'm trying to delete the first id in a structure. It used to work, but now it just returns "ЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭ" (repeated russian letter). I tried reinstalling VS, didn't help. I know it works because I tried it on an online compiler.
These two warnings also point to the delete function, which I'm guessing is the problem.
Warning C4156 deletion of an array expression without using the array form of 'delete'; array form substituted
Warning C4154 deletion of an array expression; conversion to pointer supplied
Here is the code itslef:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include <locale.h>
#include <iostream>
#pragma warning (disable: 4703) //disables warning of uninitialized variable j
using namespace std;
#define MAXDL 9
struct el_sp
{
char id[MAXDL];
struct el_sp* sled;
};
void vkl(struct el_sp** p, char t_id[]) //enters the entered ID's from keyboard into the struct
{
struct el_sp* pt,
* k, * j;
pt = (struct el_sp*)malloc(sizeof(struct el_sp));
strcpy_s(pt->id, t_id);
if (*p == NULL || strcmp(pt->id, (*p)->id) < 0)
{
pt->sled = *p; *p = pt;
}
else
{
k = *p;
while (k != NULL && strcmp(pt->id, k->id) >= 0)
{
j = k; k = k->sled;
}
j->sled = pt; pt->sled = k;
}
}
void pech_sp(struct el_sp* p) //prints the struct
{
struct el_sp* i;
char* o;
printf("\Result:\n");
for (i = p; i != NULL; i = i->sled)
puts(i->id);
}
int main() {
setlocale(LC_ALL, "RUS");
struct el_sp* p;
unsigned n;
unsigned i;
char t_id[MAXDL];
printf("\nEnter the amount of identificators\n n=");
scanf_s("%u", &n);
getchar();
p = NULL;
printf("Enter the identificators (press enter after each one)\n");
for (i = 1; i <= n; i++)
{
gets_s(t_id);
vkl(&p, t_id);
}
delete p->id;
pech_sp(p);
return 0;
}
P.S. Delete does the same thing whatever i try, in any code
P.S.S. Sorry for bad formatting, it's the way our prof needs it
Don't call delete p->id. It serves no purpose except to crash your program: neither it nor the struct it is in was allocated by new.
Also, never use delete to try to free malloced memory, or free to free newed memory.
Did you want to delete the entire first node? Then do something like
el_sp *oldp = p;
p = p->next;
free(oldp);
Deleting a node in the middle is actually a bit easier. Use "chasing pointers" that point to the previous element (prev) and the current element (cur). If cur is the node you want to delete, simply do
prev->next->next = cur->next;
delete cur;
(Assuming you allocate nodes with new, which you should!)
I understand that sometimes professors want things their way, but it's just as important to know what would be the most straightforward way to achieve your goals.
That's what I came up with. Note that there's no manual memory management, the sorting is automated, and you can easily replace the container type. In most cases the vector will be perfectly adequate - the list should only be used if the benchmarks show that you get better performance. In most cases - you won't (contrary to what professors may tell you: trust reality over teachings).
#include <algorithm>
#include <clocale>
#include <iostream>
#include <list>
#include <vector>
struct El_Sp
{
std::string id;
};
#if 1
using El_Spy = std::vector<El_Sp>;
#else
using El_Spy = std::list<El_Sp>;
#endif
template <> struct std::less<El_Sp>
{
bool operator()(const El_Sp &l, const El_Sp &r) const
{ return l.id < r.id; }
};
std::istream &operator>>(std::istream &in, El_Sp &el_sp)
{
return in >> el_sp.id;
}
std::ostream &operator<<(std::ostream &out, const El_Sp &el_sp)
{
return out << el_sp.id;
}
std::ostream &operator<<(std::ostream &out, const El_Spy &el_spy)
{
for (auto &el : el_spy)
out << el << '\n';
return out;
}
template <typename Container, typename T, typename Pred = std::less<typename Container::value_type>>
auto insert_sorted(Container &cont, T &&item, Pred pred = {})
{
return cont.insert(
std::upper_bound(std::begin(cont), std::end(cont), std::as_const(item), pred),
std::forward<T>(item));
}
void enter_id(El_Spy &el_spy)
{
El_Sp el;
std::cin >> el;
insert_sorted(el_spy, el);
}
int main()
{
El_Spy el_spy;
std::setlocale(0, "");
size_t n = 0;
std::cout << "Введите количество идентификаторов n=";
std::cin >> n;
std::cout << "Введите идентификаторы. Нажмите Enter после каждого.\n";
while (n--)
enter_id(el_spy);
std::cout << "Идентификаторы:\n" << el_spy;
}
Example session:
Введите количество идентификаторов n=3
Введите идентификаторы. Нажмите Enter после каждого.
Алла
Дарья
Вера
Идентификаторы:
Алла
Вера
Дарья
When using std::vector, the insertion sort isn't really necessary - you could use std::sort after all identifiers have been entered:
int main()
{
std::setlocale(0, "");
size_t n = 0;
std::cout << "Введите количество идентификаторов n=";
std::cin >> n;
El_Spy el_spy(n);
std::cout << "Введите идентификаторы. Нажмите Enter после каждого.\n";
for (auto &el_sp : el_spy)
std::cin >> el_sp;
std::sort(std::begin(el_spy), std::end(el_spy), std::less<El_Sp>());
std::cout << "Идентификаторы:\n" << el_spy;
}
struct el_sp
{
char id[MAXDL];
struct el_sp* sled;
};
id is a statically allocated array. It cannot be deleted.
delete p->id;
The above is wrong. Deleting a pointer whose memory is not allocated by new leads to undefined behaviour.
You should have
delete p;
And after deletion, you should not use p. So pech_sp should be called before rather than after.
pech_sp(p);
delete p;
Related
I implement the stack with a minimum. In this program, I get an error from valgrind. Something is wrong with the push() and main() functions. When I add delete st; to the push() function, I get even more errors. I check it through valgrind ./a.out. Sorry for the long code. I also wrote the rest of the functions for stack. But there is no error in them, I left those in the code where there may be an error.
#include <cstring>
#include <iostream>
struct Stack {
int data;
int min;
Stack* next;
};
void Push(Stack** top, int n) {
Stack* st = new Stack();
st->data = n;
if (*top == NULL) {
*top = st;
(**top).min = n;
} else {
st->min = ((n <= (**top).min) ? n : (**top).min);
st->next = *top;
*top = st;
}
std::cout << "ok" << std::endl;
}
void Pop(Stack** top) {
if (*top != NULL) {
std::cout << (**top).data << std::endl;
*top = (*top)->next;
} else {
std::cout << "error" << std::endl;
}
}
int main() {
Stack* top = nullptr;
int m;
std::cin >> m;
std::string str;
for (int i = 0; i < m; ++i) {
std::cin >> str;
if (str == "push") {
int value;
std::cin >> value;
Push(&top, value);
}
if (str == "pop") {
Pop(&top);
}
}
delete top;
}
When you just delete top, you destruct it (in your case it's nothing, but you can distract yourself for reading about destructors if interested) and free the dynamic memory allocated for top. However, you actually want to also delete top->next, top->next->next (if present) etc. A hotfix:
while (top) { // same as "while (top != nullptr) {"
Stack* next = top->next; // we can't use `top` after we `delete` it, save `next` beforehand
delete top;
top = next;
}
Now, about more general things. The course teaches you some really old C++ (almost just plain C; even C here is bad though). At the very least, your whole Push() can be replaced (thanks to lvalue references (Type&), std::min and aggregate initialization) with:
void push(Stack*& top, int n) {
top = new Stack{n, std::min(n, top ? top->min : n), top};
std::cout << "ok\n";
}
I'm new to C++ programming. I used to write in Python
Good job. Sadly, such teaching shows C++ as something too old and horrifying.
Edit
here's a new in Push, so there should most likely be a delete in Pop
That's right (thanks to #molbdnilo). You should delete popped elements instead of just leaking them.
Im trying to write a class that stores an id and a value in an container class.
Im using an nested class as my data structure.
When im compiling the code sometimes it prints perfectly, sometimes it prints nothing and sometimes it prints half of the data then stops.
When i debug the code the same weird behavior occours, when it fails during debug it throws an error "Map.exe has triggered a breakpoint.", the Error occours in the print method when im using cout.
cmap.h
#pragma once
class CMap
{
public:
CMap();
~CMap();
CMap& Add(int id, int value);
void print() const;
private:
class container
{
public:
~container();
int container_id = 0;
int container_value = 0;
};
container* p_komp_;
int dim_ = -1;
void resize();
};
cmap.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
CMap::CMap()
{
p_komp_ = new container[0];
}
CMap::~CMap()
{
p_komp_ = nullptr;
cout << "destroy cmap";
}
CMap& CMap::Add(int id, int value)
{
resize();
p_komp_[dim_].container_id = id;
p_komp_[dim_].container_value = value;
return *this;
}
void CMap::resize()
{
container* temp_array = new container[++dim_];
if (dim_ == 0)
{
temp_array[0].container_id = p_komp_[0].container_id;
temp_array[0].container_value = p_komp_[0].container_value;
}
for (unsigned i = 0; i < dim_; i++)
{
temp_array[i].container_id = p_komp_[i].container_id;
temp_array[i].container_value = p_komp_[i].container_value;
}
p_komp_ = temp_array;
}
void CMap::print() const
{
for (unsigned i = 0; i <= dim_; i++)
{
cout << p_komp_[i].container_id;
cout << p_komp_[i].container_value;
}
}
CMap::container::~container()
{
cout << "destruct container";
}
Map.cpp
#include "cmap.h"
#include <iostream>
using namespace std;
void main(void)
{
CMap m2;
m2.Add(1, 7);
m2.Add(3, 5);
m2.print();
}
These two things are a possible reason for your problem:
int dim_ = -1;
and
container* temp_array = new container[++dim_];
When you allocate, you increase dim_ from -1 to 0. That is you create a zero-sized "array", where every indexing into it will be out of bounds and lead to undefined behavior.
You also have memory leaks since you never delete[] what you new[]. I didn't look for more problems, but there probably a more.
And an "array" (created at compile-time or through new[]) will have indexes from 0 to size - 1 (inclusive). You seem to think that the "size" you provide is the top index. It's not, it's the number of elements.
It seems to me that you might need to take a few steps back, get a couple of good books to read, and almost start over.
I am trying to implement a hash table data structure in C++, but every time i run the program i get a run time error(SIGSEGV, segmentation fault) in line number 86 like here.
i.e.: putInHash(str,hashTable,m); in main().
This is my code:
#include <iostream>
#include<string.h>
#include<math.h>
#include<stdlib.h>
using namespace std;
typedef struct node
{
struct node *next,*prev;
string data;
}node;
int hashCode(string str)
{
char arr[str.size()+1];
strcpy(arr,str.c_str());
int code=0;
for(int i=0;i<str.size();i++)
{
code+=((i+1)*((int)arr[i]));
}
return code;
}
int compress(int k,int m)
{
double a=(sqrt(5.0)-1)/2;
return floor(m*(fmod(k*a,1)));
}
void display(node* hashTable[],int m)
{
for(int i=0;i<m;i++)
{
cout<<i<<":\n";
node* p=hashTable[i];
while(p!=NULL)
{
cout<<p->data<<" , ";
}
cout<<"\n";
}
}
void putInHash(string str,node* hashTable[],int m)
{
int k=hashCode(str);
int bucket=compress(k,m);
if(hashTable[bucket]==NULL)
{
hashTable[bucket]=(node*)malloc(sizeof(node));
hashTable[bucket]->prev=NULL;
hashTable[bucket]->next=NULL;
hashTable[bucket]->data=str;
}
else
{
node* temp=(node*)malloc(sizeof(node));
temp->data=str;
temp->next=hashTable[bucket];
hashTable[bucket]->prev=temp;
temp->prev=NULL;
hashTable[bucket]=temp;
}
}
int main()
{
cout<<"Enter number of strings to add in hash table: ";
long int n;
cin>>n;
cout<<"\n";
int m=13;
node* hashTable[m];
for(int i=0;i<m;i++)
{
hashTable[i]=NULL;
}
string str;
cout<<"Enter the strings:\n";
for(int i=0;i<n;i++)
{
cin>>str;
putInHash(str,hashTable,m);
}
display(hashTable,m);
return 0;
}
I thought it might be due to passing the string, but it turned out this wasn't the case.
Can somebody please guide me through it.
I think the error may be in passing the hashTable[] as an argument.
I can't reproduce your problem (I'm using clang++ in a Linux platform and I suppose that your problem is platform dependent) but I see something that can explain it.
You use malloc() to allocate memory for a struct with a std::string in it.
This is bad.
Really, really bad.
Because malloc() can allocate the memory but can't construct the data member in it.
In C++ you should use new; at least, allocating not trivial objects (std::string isn't trivial).
// node* temp=(node*)malloc(sizeof(node)); // DANGEROUS
node * temp = new node;
This is the problem that cause the sigsegv (I suppose) but your code has a lot of other problem.
Example: the while in display() goes in loop because p remain unchanged; you should change display() in this way
void display (node * hashTable[], int m)
{
node * p;
for(int i=0;i<m;i++)
{
cout << i << ":\n";
for ( p = hashTable[i] ; p ; p = p->next )
cout << p->data << " , ";
cout << "\n";
}
}
Another important point: variable length arrays isn't C++; it's C (C99). So this lines are wrong
char arr[str.size()+1];
node* hashTable[m];
You don't need the first (absolutely useless) and you can simplify hashcode() in this way (and please, pass the strings by const reference, when possible)
int hashCode (const string & str)
{
int code = 0;
for ( int i = 0 ; i < str.size() ; ++i )
code += (i+1) * int(str[i]);
return code;
}
About hashTable, you can substitute it with a std::vector
// node* hashTable[m]; no C++
//for(int i=0;i<m;i++) // useless
//{ // useless
// hashTable[i]=NULL; // useless
//} // useless
std::vector<node *> hashTable(m, NULL); // m NULL node pointers
Obviously, putInHash() should be
void putInHash (string str, std::vector<node*> & hashTable, int m)
and display()
void display (const std::vector<node*> & hashTable, int m)
And remember to free the allocated memory.
p.s.: sorry for my bad English.
--- EDIT ---
phonetagger is right: deleting the memory (a vector o linked nodes) isn't trivial.
I suggest a function like the following
void recursiveFreeNode (node * & nd)
{
if ( nd )
{
recursiveFreeNode(nd->next);
delete nd; // added with EDIT 2; sorry
nd = NULL; // useless, in this, case, but good practice
}
}
and call it (for every node of the vector) in main(), after display() calling
for ( unsigned ui = 0U ; ui < hashTable.size() ; ++ui )
recursiveFreeNode(hashTable[ui]);
--- EDIT 2 ---
Sorry: I've forgot the more important line: delete node (thanks phonetagger).
Following the other suggestion of phonetagger, I propose a not-recursive function for deleting the hashtable's node
void loopFreeNode (node * & nd)
{
node * tmp;
for ( ; nd ; nd = tmp )
{
tmp = nd->next;
delete nd;
}
nd = NULL;
}
Obviously the for loop, to use loopFreeNode(), should be
for ( unsigned ui = 0U ; ui < hashTable.size() ; ++ui )
loopFreeNode(hashTable[ui]);
Been wracking my mind all day trying to hammer out the underlying data structures for a challenge assignment in one of my programming classes.
The problem is as follows:
Given an assortment of objects (each of which includes an identifier and a weight) and a supply of containers (which have a fixed weight capacity), pack all the items using as few containers as possible without overloading any of them.
I have the logic aspects hammered out using a hodgepodge of arrays, but the dynamic nature of this assignment has me wanting to optimize things by using vectors and/or linked lists.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <cstdlib>
#include <math.h>
#include <time.h>
#include <conio.h>
#include <vector>
#include <algorithm>
using namespace std;
struct Item
{
int number;
double weight;
bool operator < (const Item& str) const
{
return (weight < str.weight);
}
};
class Node
{
int number;
double weight;
Node* next;
public:
Node()
{};
void SetID(int iNum)
{
number = iNum;
};
void SetWeight(double iWeight)
{
weight = iWeight;
};
void SetNext(Node* iNext)
{
next = iNext;
}
int GetID()
{
return number;
};
double GetWeight()
{
return weight;
};
Node* Next()
{
return next;
};
};
class List
{
Node* head;
double weight;
public:
List()
{
head = NULL;
weight = 0;
};
int Size()
{
Node* tmp;
int count = 0;
for (tmp = head; tmp != NULL; tmp = tmp->Next())
{
count++;
}
return count;
};
double Weight()
{
return weight;
};
void Print()
{
Node *tmp = head;
if ( tmp == NULL )
{
cout << " E M P T Y" << endl;
return;
}
do
{
cout << setw(8) << tmp->GetID() << " | " << setw(8) << tmp->GetWeight() << endl;
tmp = tmp->Next();
} while ( tmp != NULL );
};
void Append(int iNum, double iWeight)
{
Node* newNode = new Node();
newNode->SetID(iNum);
newNode->SetWeight(iWeight);
newNode->SetNext(NULL);
Node *tmp = head;
if ( tmp != NULL )
{
while ( tmp->Next() != NULL )
{
tmp = tmp->Next();
}
tmp->SetNext(newNode);
}
else
{
head = newNode;
}
weight += iWeight;
};
};
double ItemWeights(vector<Item> iVect)
{
double total = 0;
for(int i = 0; i < iVect.size(); i++)
{
total += iVect[i].weight;
}
return total;
}
int main()
{
const double MAX_WEIGHT = 20;
vector< Item > source;
//
// Segment of code which propagates the vector data
// works fine, but is excluded for the sake of brevity
//
double totalWeight = ItemWeights(source);
// Duplicate vector of items
vector< Item > items(source);
for(int i = 0; i < items.size(); i++)
{
cout << setw(8) << items[i].number << setw(8) << items[i].weight << endl;
}
cout << "\n Total weight = " << totalWeight << endl;
cout << "\n\n Press any key to continue... ";
getch();
// Solution A-Original
// vector< vector< Item > > boxesAO( vector< Item >);
// boxesAO[0].push_back({items[items.size()].number, items[items.size()].weight});
vector< List > boxesAO;
// boxesAO[0].Append(items[items.size()].number, items[items.size()].weight);
return 0;
}
I've left some of the methods I've tried in the code (commented out) - none of which worked. As I mentioned above, I've got it working with arrays of linked lists and with 2D arrays, but the vast range of potential input makes these problematic at best. Either a bunch of empty lists taking up space or, worse, not having enough.
I'm thinking that vector< List > is my best option, but I can't figure out how I'm supposed to access any of the List functionality.
If someone would be so helpful as to offer a suggestion for how to create a "dynamic 2D array" as well as a code example of how to access it, I would be most greatly appreciative. My deepest thanks in advance.
EDIT:
#jaredad7 ~ That's what I've been trying, but it keeps causing the program to crash.
List box;
box.Append(items[items.size()].number, items[items.size()].weight);
This works just fine - no problems whatsoever.
The earlier code propagates a 1D vector of Item structs, which also works properly.
vector< List > boxes;
boxes[0].Append(items[items.size()].number, items[items.size()].weight);
This compiles fine but crashes during execution, no matter what index is used. (I'm also using couts for debugging, and the issue most definitely lies with trying to access the List functions.)
I'm suspecting that .push_back or somesuch may be needed, but I haven't been able to find much information concerning vectors of List objects.
If you can, my first suggestion would be to go with the vector (if that is allowed). As for accessing functions/attributes of a member of a vector, it's done the same way as an array, that is:
vectorname[i].functionname(a,b,c);
The best way to do this without vectors would be to use your nodes as the item container (a struct), and handle node-creation, deletion, etc. in your list class. Then, you would only really need one container for as many objects of one type as you need. You can make the type dynamic (although it appears you only need doubles for this project) by adding a class template (use google if you are unfamiliar with templates in C++). This will allow your user to make a container for each type of data (much like a vector).
For my current assignment, I have to use the following header file,
#ifndef STACK_H
#define STACK_H
template <class T, int n>
class STACK
{
private:
T a[n];
int counter;
public:
void MakeStack() {
counter = 0;
}
bool FullStack() {
return (counter == n) ? true : false ;
}
bool EmptyStack() {
return (counter == 0) ? true : false ;
}
void PushStack(T x) {
a[counter] = x;
counter++;
}
T PopStack() {
counter--;
return a[counter];
}
};
#endif
To write a program that will take a sentence, store it into the "stack", and then display it in reverse, and I have to allow the user to repeat this process as much as they want. The thing is, I am NOT allowed to use arrays (otherwise I wouldn't need help with this), and am finding myself stumped.
To give an idea of what I am attempting, here is my code as of posting, which obviously does not work fully but is simply meant to give an idea of the assignment.
#include <iostream>
#include <cstring>
#include <ctime>
#include "STACK.h"
using namespace std;
int main(void)
{
auto time_t a;
auto STACK<char, 256> s;
auto string curStr;
auto int i;
// Displays the current time and date
time(&a);
cout << "Today is " << ctime(&a) << endl;
s.MakeStack();
cin >> curStr;
i = 0;
do
{
s.PushStack(curStr[i]);
i++;
} while (s.FullStack() == false);
do
{
cout << s.PopStack();
} while (s.EmptyStack() == false);
return 0;
} // end of "main"
UPDATE
This is my code currently
#include <iostream>
#include <string>
#include <ctime>
#include "STACK.h"
using namespace std;
time_t a;
STACK<char, 256> s;
string curStr;
int i;
int n;
// Displays the current time and date
time(&a);
cout << "Today is " << ctime(&a) << endl;
s.MakeStack();
getline(cin, curStr);
i = 0;
n = curStr.size();
do
{
s.PushStack(curStr[i++]);
i++;
}while(i < n);
do
{
cout << s.PopStack();
}while( !(s.EmptyStack()) );
return 0;
You're on the right track, but you shouldn't be looping until the stack is full -- there are no guarantees curStr consists of at least 256 characters. Instead, loop like as follows...
int n = curStr.size();
do {
s.PushStack(curStr[i++]);
} while (i < n);
Now, you should really not write <bool-expr> == false or <bool-expr> == true... instead, merely write !<bool-expr> and <bool-expr>, respectively. You don't need all of your auto storage specifiers on the local variables, either. Your professor should also look into using the constructor rather than using MakeStack.
edit: It appears you had some trouble translating my code. You only need to i++ once per loop -- this increments our position in the string. As you are doing it now, you are actually incrementing the position twice and thus only pushing every other character.
Use a linked list instead of array in stack.
In the linked list, always store the tail pointer of your list's last node. Each node maintains a reference to your prev node.
A <--- B <---- C (tail)
push:
A <--- B <---- C <---- D (tail)
pop:
A <--- B <---- C (tail)
// D is popped out
when the tail == null, you know it is an empty stack