I'm learning cpp by myself (I hope I didn't scare you off already), I understand what a pointer or a reference is and I think I get what a reference to a pointer is.
I've written a code that crashes at delete[] ranking; :
open(file) is just a simple function to open a txt file that contains a string and 3 integers each line which goes into zuzel structure:
void read_file(std::ifstream & file, zuzel *& ranking)
{
if(!open(file))
return; //exit function if reading a file failed
int size = 1;
while(!file.eof())
{
zuzel * update = new zuzel[size];
if(ranking != NULL) memcpy(update, ranking, (size-1)*sizeof(*ranking)); //copy existing contents
file >> update[size - 1].nazwa >> update[size - 1].zawodnicy >> update[size - 1].mecze >> update[size - 1].punkty;// add a new team
delete[] ranking; //delete old data
std::cout << "tst"; //just to see if it crashes
ranking = update;
size++;
}
}
int main()
{
zuzel * rank;
std::ifstream file;
read_file(file, rank);
return 0;
}
I found out that you shouldn't delete something that you didn't new, but for example that code doesn't crash :
void funk(int *& a)
{
delete[] a;
}
int main()
{
int a[3] = {3, 4, 6};
int * p = a;
funk(p);
return 0;
}
How can I fix that crash? I'd be much obliged for some simple explanation why does it behave that way.
It will be enough to write
zuzel * rank = 0;
As for the second code snippet then it has undefined behaviour.
zuzel * rank;
//somewhere in read_file:
delete[] ranking; //ranking is a reference to pointer;
//in your case it's referernce to uninitialized pointer rank
Because rank is not initialized, it points to a unknown portion of memory, and your code simply tryes to delete[] the portion anyway...
You need to do set a pointer to address 0 by using one of these:
zuzel * rank=nullptr; //in C++11
zuzel * rank=NULL; //before C++11
zuzel * rank=0; //also legal, but I not recommend this
0 is the special value for any pointer, meaning that it points to nothing.
When you pass pointer set to 0 to delete[] or delete they simply do nothing.
Since you're learning. Please accept this example of how you might prefer to do it. You will find that it's exception-safe and avoids using pointers (and therefore avoids the need for memory management)
main.cpp:
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <algorithm>
#include <iterator>
struct zuzel
{
std::string nazwa, zawodnicy, mecze, punky;
};
std::ostream& operator<<(std::ostream& os, const zuzel& z)
{
return os << z.nazwa << ", "
<< z.zawodnicy << ", "
<< z.mecze << ", "
<< z.punky;
}
std::vector<zuzel> read_zuzels(std::string filename)
{
std::vector<zuzel> results;
std::ifstream f(filename.c_str());
f.exceptions(std::ios::badbit);
while(!f.eof())
{
// add a new team
zuzel new_zuzel;
f >> new_zuzel.nazwa
>> new_zuzel.zawodnicy
>> new_zuzel.mecze
>> new_zuzel.punky;
results.push_back(new_zuzel);
}
return results;
}
using namespace std;
int main()
{
vector<zuzel> zuzels = read_zuzels("input.txt");
copy(zuzels.begin(), zuzels.end(), ostream_iterator<zuzel>(cout, "\n"));
return 0;
}
input.txt:
foo1 bar1 baz1 bazzer1
foo2 bar2 baz2 bazzer2
output:
Compiling the source code....
$g++ main.cpp -o demo -lm -pthread -lgmpxx -lgmp -lreadline 2>&1
Executing the program....
$demo
foo1, bar1, baz1, bazzer1
foo2, bar2, baz2, bazzer2
Related
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;
I'm trying to instantiate a class for a specific implementation of a symbol table and, following the instructions for the project, I'm doing it via a pointer. My constructor does a lot as it is the thing building the symbol table from a text file, but I'm getting a Segmentation fault error at the end of the constructor. What I don't understand is what exactly is giving me this error. I've done a bit of debugging and it seems my constructor is running just fine, as it gets to the breakpoint I put at the very last bracket and all the data is in the vector as I expected. When it tries to step out of the constructor and back to the main file, though, it gives me that error.
The main file is as follows:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string.h>
#include <time.h>
using namespace std;
#include "tabeladesimbolos.hpp"
typedef char * String;
typedef int * Integer;
int main(int argc, char *argv[])
{
fstream arqTexto;
/* abra arquivo com texto */
arqTexto.open(argv[1]);
if (arqTexto.fail())
{
cout << "ERRO: arquivo" << argv[1] << "nao pode ser aberto.\n";
exit(EXIT_FAILURE);
}
arqTexto.close();
string nome_arquivo = argv[1];
/* crie a ST*/
cout << "criando ST...\n";
/* usadas para medir tempo de processamento */
clock_t start, end;
double elapsed = 0;
start = clock();
vetorDes *st = new vetorDes(nome_arquivo);
end = clock();
/* calcule o tempo */
elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
cout << "arquivo lido e ST construida em " << elapsed << " segundos\n";
delete st;
return 0;
}
The error happens in the following line:
vetorDes *st = new vetorDes(nome_arquivo);
The file with the constructor (tabeladesimbolos.hpp) is:
#include <string>
#include <string.h>
#include <iostream>
#include <fstream>
#include <vector>
typedef char * String;
typedef int * Integer;
using namespace std;
struct Valor
{
String chave;
Integer valor;
};
class vetorDes
{
vector<Valor> vetor;
public:
vetorDes(string nomeArquivo);
void insere(String chave, Integer valor);
Integer devolve(String chave);
};
vetorDes::vetorDes(string nomeArquivo)
{
ifstream arqTexto;
String palavra;
Integer aux = nullptr;
vetor.reserve(10000);
arqTexto.open(nomeArquivo);
while (arqTexto >> palavra)
{
aux = devolve(palavra);
if (aux == nullptr)
{
int* um = new int;
*um = 1;
insere(palavra, um);
}
else
{
(*aux)++;
}
}
}
void vetorDes::insere(String chave, Integer valor)
{
Valor *aux = new Valor;
aux->chave = (String) malloc(20*sizeof(char));
strcpy(aux->chave, chave);
aux->valor = valor;
int maxsize = vetor.max_size();
int currentsize = vetor.size();
vetor.push_back(*aux);
return;
}
Integer vetorDes::devolve(String chave)
{
for (std::size_t i = 0; i < vetor.size(); ++i)
{
String teste = vetor[i].chave;
if (!strcasecmp(teste, chave))
{
return vetor[i].valor;
}
}
return nullptr;
}
My debugger gets me to that last } in the constructor without error, which leads me to believe the problem is with the way I allocate something as it only comes up when the program tries to finish the "new vetorDes" call.
The full error message is:
Program received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0x3b002e6f746e6174) at malloc.c:3103
What am I doing wrong? What am I missing?
String palavra;
...
while (arqTexto >> palavra)
I didn't see anything between declaring palavra, which is a pointer, and reading into it, that made palavara point anywhere. The pointer is uninitialized, so it points to some random place, and you are reading your data into that random place. Anything can happen then, except anything good.
__GI___libc_free (mem=0x3b002e6f746e6174)
The 0x3b002e6f746e6174 is obviously invalid pointer:
it's not in canonical form,
its tail looks like ASCII string tanto.
It is safe to assume that you have some kind of heap overflow (or other heap corruption). Use Valgrind or Address Sanitizer to find the bug.
As N.M. noted, you are doing yourself a great disservice by hiding pointers behind these typedefs:
typedef char * String;
typedef int * Integer;
The bug would be much more noticeable if you didn't:
char *palavra; // uninitialized pointer
...
while (arqTexto >> palavra) // BUG: writes to random memory
I am struggling to find the correct format for initializing a (private) array within a class and getting/setting the values from outside the class.
My code is semi-functional, but feels awkward in incorrectly formatted.
It is returning only the first element of the array, I want it to return all the contents. Read code comments for additional details.
Note: This is (a very small part of) a project I am working on for school -- an array must be used, not a vector or list.
student.h
class Student {
public:
// Upon researching my issue, I read suggestions on passing pointers for arrays:
void SetDaysToCompleteCourse(int* daysToCompleteCourse[3]);
int* GetDaysToCompleteCourse(); // Ditto # above comment.
private:
int daysToCompleteCourse[3];
student.cpp
#include "student.h"
void Student::SetDaysToCompleteCourse(int* daysToCompleteCourse) {
// this->daysToCompleteCourse = daysToCompleteCourse; returns error (expression must be a modifiable lvalue)
// Feels wrong, probably is wrong:
this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
this->daysToCompleteCourse[1] = daysToCompleteCourse[1];
this->daysToCompleteCourse[2] = daysToCompleteCourse[2];
}
int* Student::GetDaysToCompleteCourse() {
return daysToCompleteCourse;
}
ConsoleApplication1.cpp
#include "pch.h"
#include <iostream>
#include "student.h"
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
int* ptr = daysToCompleteCourse;
student.SetDaysToCompleteCourse(ptr);
std::cout << *student.GetDaysToCompleteCourse(); // returns first element of the array (1).
}
I gave this my best shot, but I think I need a nudge in the right direction.
Any tips here would be greatly appreciated.
I would say:
// student.h
class Student
{
public:
// If you can, don't use numbers:
// you have a 3 on the variable,
// a 3 on the function, etc.
// Use a #define on C or a static const on C++
static const int SIZE= 3;
// You can also use it outside the class as Student::SIZE
public:
void SetDaysToCompleteCourse(int* daysToCompleteCourse);
// The consts are for "correctness"
// const int* means "don't modify this data" (you have a setter for that)
// the second const means: this function doesn't modify the student
// whithout the const, student.GetDaysToCompleteCourse()[100]= 1 is
// "legal" C++ to the eyes of the compiler
const int* GetDaysToCompleteCourse() const; // Ditto # above comment.
Student()
{
// Always initialize variables
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= 0;
}
}
private:
int daysToCompleteCourse[SIZE];
// On GCC, you can do
//int daysToCompleteCourse[SIZE]{};
// Which will allow you not to specify it on the constructor
};
// student.cpp
void Student::SetDaysToCompleteCourse(int* newDaysToCompleteCourse)
{
// It's not wrong, just that
// this->daysToCompleteCourse[0] = daysToCompleteCourse[0];
// use another name like newDaysToCompleteCourse and then you can suppress this->
// And use a for loop
for (int i= 0; i < SIZE; i++) {
daysToCompleteCourse[i]= newDaysToCompleteCourse[i];
}
}
const int* Student::GetDaysToCompleteCourse() const
{
return daysToCompleteCourse;
}
// main.cpp
#include <iostream>
std::ostream& operator<<(std::ostream& stream, const Student& student)
{
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
stream << toShow[i] << ' ';
}
return stream;
}
int main()
{
Student student;
int daysToCompleteCourse[3] = { 1, 2, 3 };
// You don't need this
//int* ptr = daysToCompleteCourse;
//student.SetDaysToCompleteCourse(ptr);
//You can just do:
student.SetDaysToCompleteCourse(daysToCompleteCourse);
// On C++ int* is "a pointer to an int"
// It doesn't specify how many of them
// Arrays are represented just by the pointer to the first element
// It's the FASTEST and CHEAPEST way... but you need the SIZE
const int* toShow= student.GetDaysToCompleteCourse();
for (int i= 0; i < Student::SIZE; i++) {
std::cout << toShow[i] << ' ';
// Also works:
//std::cout << student.GetDaysToCompleteCourse()[i] << ' ';
}
std::cout << std::endl;
// Or you can do: (because we defined operator<< for a ostream and a Student)
std::cout << student << std::endl;
}
You can check out it live here: https://ideone.com/DeJ2Nt
I am working on a C++ project for school in which the program will read in a list of numbers from a text file, store them in a dynamic array, then print them out to another text file. To be honest I'm a little lost with the pointers in this, and I am getting the error "A value of type "void" cannot be used to initialize an entity of type "int"" in my main source file.
Main.cpp (this is where I'm getting the error):
#include "dynamic.h"
int main
{
readDynamicData("input.txt","output.txt");
}
dynamic.cpp (the skeleton for the program):
#include "dynamic.h"
void readDynamicData(string input, string output)
{
DynamicArray da; //struct in the header file
da.count = 0;
da.size = 5; //initial array size of 5
int *temp = da.theArray;
da.theArray = new int[da.size];
ifstream in(input);
ofstream out(output);
in >> da.number; //prime read
while (!in.fail())
{
if (da.count < da.size)
{
da.theArray[da.count] = da.number;
da.count++;
in >> da.number; //reprime
}
else grow; //if there are more numbers than the array size, grow the array
}
out << "Size: " << da.size << endl;
out << "Count: " << da.count << endl;
out << "Data:" << endl;
for (int i = 0; i < da.size; i++)
out << da.theArray[i];
in.close();
out.close();
delete[] temp;
}
void grow(DynamicArray &da) //this portion was given to us
{
int *temp = da.theArray;
da.theArray = new int[da.size * 2];
for (int i = 0; i<da.size; i++)
da.theArray[i] = temp[i];
delete[] temp;
da.size = da.size * 2;
}
and dynamic.h, the header file:
#include <iostream>
#include <string>
#include <fstream>
#ifndef _DynamicArray_
#define _DynamicArray_
using namespace std;
void readDynamicData(string input, string output);
struct DynamicArray
{
int *theArray;
int count;
int size;
int number;
};
void grow(DynamicArray &da);
#endif
you have to add parenthesis to main or any function:
int main(){/*your code here ...*/};
2- you are using an unitialized objct:
DynamicArray da; //struct in the header file
da.count = 0;
da.size = 5; //initial array size of 5
so int* theArray is a member data and is uninitialized so welcome to a segfault
all the members of da are not initialized so you have to do before using it.
3- also you add parenthesis to grow function:
else grow(/*some parameter here*/); // grow is a function
4- using namespace std; in a header file is a very bad practice.
tip use it inside source
5- why making inclusion of iostream and string.. before the inclusion guard??
correct it to:
#ifndef _DynamicArray_
#define _DynamicArray_
#include <iostream>
#include <string>
#include <fstream>
/*your code here*/
#endif
main is a function so it needs brackets:
int main(){
// your code
return 0; // because it should return intiger
}
And. Your grow is also a function, so if you want to call it you write grow() and it needs DynamicArray as a parameter.
It is impossible to write working programs on C/C++ any programming language not knowing a basic syntax.
I'm working on a project and every time I go to set example[4].m_dArray[3], the program crashes. I can set the value of every other variable up until I get to example[4].m_dArray[3]. Any help would be appreciated!
Prog1Class.h:
#include "Prog1Struct.h"
#pragma once
#include <iostream>
#include <string.h>
using namespace std;
class Prog1Class
{
private:
Prog1Struct example[4];
public:
Prog1Class();
~Prog1Class ();
void setStructData();
void getStructData();
void ptrFunction();
void refFunction();
void printStruct();
void printData();
};
Prog1Struct.h:
#pragma once
#include <string.h>
struct Prog1Struct {
int m_iVal;
double m_dArray[4];
char m_sLine[80];
};
Prog1Class.cpp:
#include "Prog1Class.h"
#include "Prog1Struct.h"
#include <iostream>
#include <string.h>
using namespace std;
Prog1Class::Prog1Class()
{
}
Prog1Class::~Prog1Class()
{
delete &example[4];
}
int main()
{
Prog1Class *aClass = new Prog1Class();
aClass->setStructData();
aClass->printData();
return 0;
}
void Prog1Class::setStructData()
{
for(int i=0;i<5;i++)
{
cout << "Enter an integer: ";
cin >> example[i].m_iVal;
for(int j=0;j<5;j++)
{
cout << endl << "Enter a double: ";
cin >> example[i].m_dArray[j];
}
cout << endl << "Enter a string: ";
cin.ignore(256,'\n');
cin.getline(example[i].m_sLine, 80, '\n');
cout << endl;
}
}
void Prog1Class::getStructData()
{
}
void Prog1Class::printData()
{
for(int i=0;i<5;i++)
{
cout << example[i].m_iVal;
for(int j=0;j<5;j++)
{
cout << example[i].m_dArray[j];
}
cout << example[i].m_sLine;
}
}
You need to change this
class Prog1Class
{
private:
Prog1Struct example[4];
to this
class Prog1Class
{
private:
Prog1Struct example[5];
In C++ arrays start at index 0, so an array of size 4 has valid indexes 0 upto 3. You're using example[4] so you need an array of (at least) size 5.
You also need to remove delete &example[4]; from your destructor as well.
First , delete &example[4]; should be delete [] example;
Second, where did you allocate memory for example?
You need to show the way the example object is declared? I'd suspect some mis-allocated or mis-declared problem with it. Your setStructureData doesn't do anything ostensibly wrong (assuming the array sizes match and the size of the string is fitting - it is a char array, not a pointer, correct?).
for (int i = 0; i < 5; i++)
// ^^^^^
Your for loops should have an ending condition with i < 4 since your arrays have only 4 spaces. Moreover, your delete should be delete[] example;.
Array deletion is delete [] example, not your way. Also, to use delete data needs to be allocated with new
Here is small example how to use new and delete
#include <iostream>
struct foo
{
foo() {std::cout <<"constructed\n";}
~foo() {std::cout <<"destroyed\n";}
};
int main ()
{
foo * pt;
pt = new foo[3];
delete[] pt;
return 0;
}
Also the output:
constructed
constructed
constructed
destroyed
destroyed
destroyed
I gave a lesson about new/delete and just now seen real problem:
example[4] is out of bounds. If you declare array with 4 elements it means you have indexes 0, 1, 2, 3 and nothing more.