dynamic memory array using logic loop - c++

I have a question related to dynamic memory. I have pretty much given up on using it and use vectors instead now, but would still love to know why the following type of code often gives me a runtime error with bad memory allocation. Is there a way to do this with dynamic memory?
The idea is basically using a loop to increase the size of an array, based on some condition. As stated, I now only use vector.push_back() for this, but thought I'd post and see if there were any insights.
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
#include <new>
int main()
{
ifstream infile.open("file.txt");
string str1, str2; stringstream os;
int length;
string *vecarr = new string[length];
length = 0;
while(!infile.eof())
{
getline(infile,str1);
if(str1.find("expression") != string::npos)
{
length++;
vecarr[length-1] = str1;
}
}
infile.close();
return 0;
}

length is uninitialized in the expression new string[length], so this is plain undefined behaviour. You must not read an uninitialized int variable.

Related

How do i make an array which is a class object and has a compile time size?

I'm new at this and haven't done much, but I'm really stuck on making a compile-time sized array, which is a class object. And maybe there's a way to save all the information from file, while occupying less of memory? Here's a bit of my code:
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
class Beer
{
public:
string name;
string rating;
string country;
string alc;
string type;
};
int main() //Function uses ''bytes of stack/exceeds analyze:stacksize '16384'.
//Consider moving some data to heap
{
ifstream file("beer.txt");
if (!file.good())
{
cout << "Error. File was not found." << endl;
exit(EXIT_FAILURE);
}
else
{
int count;
string line;
ifstream file("beer.txt");
int count = 0;
for (int i = 0; !file.eof(); i++)
{
getline(file, line);
count++;
}
const int SIZE = count; //<- this is the place i'm struggling with
Beer allBeers[SIZE]; //expression must have a constant value
Beer currentBeer;
for (int i = 0; !file.eof(); i++)
{
getline(file, currentBeer.name, '\t');
getline(file, currentBeer.rating, '\t');
getline(file, currentBeer.country, '\t');
getline(file, currentBeer.alc, '\t');
getline(file, currentBeer.type, '\n');
allBeers[i] = currentBeer;
}
}
file.close();
return 0;
}
If you don't know the size of an array during compile time, just use a std::vector:
#include <vector>
// ...
// const int SIZE = count; // you don't need this anymore
std::vector<Beer> allBeers;
// ...
allBeers.push_back(currentBeer); // to append it to your 'array'
vectors behave very similar to arrays, but when using push_back they 'grow' if needed. Notice that they might reserve a little more memory than is necessary so they don't have to grow every time you call push_back. To free this reserved memory you can call shrink_to_fit once afterwards.
If you don't want to use shrink_to_fit you can also make the vector precisely the size you need beforehand using
const int SIZE = count;
std::vector<Beer> allBeers;
allBeers.reserve(SIZE);
If you don't know the size at compile time, then you should use a std::vector instead.
https://en.cppreference.com/w/cpp/container/vector
#include <vector>
And then
std::vector<Beer> allBeers;
Later, to add a beer:
allBeers.push_back(currentBeer);
The main problem with your code is in the following two lines:
const int SIZE = count; //<- this is the place i'm struggling with
Beer allBeers[SIZE]; //expression must have a constant value
Now, although SIZE is defined as const it is not a compile-time constant! Further, arrays in C++ need dimensions that are compile-time constants. (Your const qualifier means only that, once initialized, the value of SIZE cannot be changed.)
The simple, "old-style-C++" way of working around this is to declare allBeers as a pointer and use the new operator to create the 'array buffer' at run-time (when the actual value of SIZE is known):
const int SIZE = count; // Don't really need this, now - could just use "count"
Beer* allBeers = new Beer[SIZE]; // You can still use allBeers[i] to access!
But, here, you shoud be sure to execute delete[] allBeers; when you're done with the array/buffer.
A more modern approach would be to use the std::vector type, in which case freeing memory takes care of itself when the object goes out of scope:
const size_t SIZE = size_t(count);
std::vector<Beer> allBeers(SIZE);
Again, you can then access using allBeers[i].
Feel free to ask for further clarification and/or explanation.

String declaration initial length when not initialised

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
int main(){
char a[20];
cout<<strlen(a)<<endl;
return 0;
}
The output of this code is 11.
Why 11? When I have not initialised it.
As stated here: http://en.cppreference.com/w/cpp/string/byte/strlen,
The behavior (of strlen(str)) is undefined if there is no null character in the character array pointed to by str.
The issue you are facing is caused by uninitialized memory. With char a[20]; you are only reserving memory space, but you are not initializing it. Those 20 bytes can have any possible value and you have no guarantees that any of them is set to 0. That causes the unespected return value of the strlen() call, you simply were lucky that the function found a byte set to 0 before it could cause a crash.
To avoid any problem you should initialize your variables before using. For a null terminated sequence of char you can initialize like so:
char a[20] = "";
Or you can use std::string instead:
#include <iostream>
#include <string>
int main() {
std::string a;
std::cout << a.length() << std::endl;
return 0;
}
The output, if you are wondering, is 0.
If you find uninitialized array's length,The behavior is undefined. if you want correct result initialize it. or use this:
int a[20] = {};
or
memset(a,'\0',20) and then after check the length.

error: incompatible types in assignment of 'char*' to 'char [4000]'

I've been trying to solve an easy problem, but I can't figure why my program doesn't work. I want to concatenate a string.
Can you help me? If so, can you also explain me why it doesn't work?
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
ifstream in("sirul.in");
ofstream out("sirul.out");
char a[4000]="a",b[4000]="b",aux[4000];
int main()
{ int n,i;
in>>n;
if(n==1)out<<"a";
if(n==2)out<<"b";
for(i=3;i<=n;i++)
{
aux=strcpy(aux,b);
b=strcat(b,a);
a=strcpy(a,aux);
}
return 0;
}
strcpy and strcat work directly on the pointer you pass in as the first argument, then also return is so that you can chain calls. As such, assigning their result back to the destination pointer is redundant. In this case, it's also invalid, as you can't reassign an array.
The fix is to just not assign the return value of those calls:
strcpy(aux,b);
strcat(b,a);
strcpy(a,aux);
However, since you are using C++, you should use std::string instead, which gives you nice value semantics for your string data.
you can not do (see 2)
char b[4000]="b";
char aux[4000];
aux /* 2 */ = strcpy(aux /* 1 */ , b);
because aux is not a pointer, but array. you can pass it as pointer argument (see 1), but you can not "collect" the result "inside" aux (see 2).
As other suggested, just remove "collection" and it will work as you expect.
char b[4000]="b";
char aux[4000];
strcpy(aux /* 1 */ , b);
// or even:
const char *s = strcpy(aux /* 1 */ , b);
Also you are mixing C and C++ in one file.
Also probably there is possibility for buffer overflow.
#include <iostream>
#include <cstring>
#include <fstream>
using namespace std;
ifstream in("sirul.in");
ofstream out("sirul.out");
char a[4000]="a",b[4000]="b",aux[4000];
int main()
{
int n,i;
cin>>n;
if(n==1)cout<<"a";
if(n==2)cout<<"b";
for(i=3;i<=n;i++)
{
strcpy(aux,b);
strcat(b,a);
strcpy(a,aux);
}
return 0;
}
check out definition os strcpy, in should be cin and out should be cout

Dynamically allocated string array, then change it's value?

I'm trying to create a string array and use a pointer to modify it. I'm not sure how to declare the pointer since strings can vary in length, and I think this is what causes the error.
My code looks something like this:
#includes <string>
#includes <iostream>
using namespace std;
string *users = NULL;
int seatNum = NULL;
cin >> seatNum;
users = new string[seatNum];
string name;
cin >> name;
users[seatNum] = name;
It throws me an Write Access Violation when I try to change its value. From what I've read it's because strings are compiled as read-only, so my question is how would I/what would I do to change it? Easy-to-understand explanations would be preferable.
You're accessing memory beyond the range of the allocated array
users = new string[seatNum];
users[seatNum] = name;
The first element is [0]. The last is [seatNum-1]
You have created an array of seatNum elements. Array element indexing starts at 0 therefore the range of valid indexes is [0, seatNum - 1]. By accessing users[seatNum] = ... you are effectively going past the last valid element of the array. This invokes UB (undefined behavior).
I see you have already made the right choice of using std::string instead of C-style strings. Why not make the same choice over arrays?
#include <string>
#include <array>
#include <iostream>
int main(int, char*[]) {
int seatNum = 0;
std::cin >> seatNum;
std::vector<std::string> users(seatNum);
std::cin >> users[0];
return 0;
}
Try to avoid pointers and C-style arrays, especially dynamic ones.
A few things:
int seatNum will be allocated on the stack and will never be NULL. You should set it to 0.
You are setting users[seatNum] which is out of bounds causing your program to crash. You
can only use indices from 0 to seatNum-1.
Updated: Chris is correct. I looked into it and strings are indeed mutable in C++.
firstly you cannot set null value to int type data
int seatNum = NULL; // wrong
int seatNum = 0; // right
secondly string bounds from 0 to seatnum -1
users[seatNum-1] = name; // right

String reverse error

Can anyone explain to me why im getting a ".exe has encountered a problem and needs close"error, it compiles and works sometimes when i fiddle with the char array, but when it does work i sometimes get strange characters at the end of the string.
#include <iostream>
using namespace std;
char* StrReverse3(char*);
char* StrReverse3(char* str)
{
char *p;
int length=0,start=0,end=0;
length=strlen(str);
for(start=0,end=length-1;end>= 0,start<=length-1;end--,start++)
{
p[start]=str[end];
}
return p;
}
int main()
{
char str[100]="Saw my reflection in snow covered hills";
StrReverse3(str);
cin.get();
return 0;
}
You are not initializing p. It's an uninitialized pointer that you are writing to.
Since you are writing this in C++, not C, I'd suggest using std::string and std::reverse:
#include <string>
#include <algorithm>
#include <iostream>
int main()
{
std::string str = "Saw my reflection in snow covered hills";
std::reverse(str.begin(), str.end());
std::cout << str;
return 0;
}
Output:
sllih derevoc wons ni noitcelfer ym waS
See it working online at ideone
char *p; is never initialized, yet p[start] is used as the destination of an assignment. Don't you get compiler warnings from this? I'm amazed it even "works sometimes".
You are accessing memory that wasn't allocated by your program (p can point anywhere!). This is the reason for the problems you have.
I strongly encourage you to
read into the topic of dynamically allocating memory with new and delete to understand a very important topic
read into the standard template library, especially std::string. You should not use raw pointers like char*, always use standard types when possible.
#include <iostream>
#include <cstring>
using namespace std;
char* StrReverse3(char* str){
int length=0,start=0,end=0;
length=strlen(str);
for(start=0,end=length-1;end > start;end--,start++){
char temp;
temp = str[start];
str[start]=str[end];
str[end]=temp;
}
return str;
}
int main(){
char str[100]="Saw my reflection in snow covered hills";
cout << StrReverse3(str);
cin.get();
return 0;
}