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

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

Related

Question of dynamic memory allocation and dynamic memory deallocation

I need someone to solve the problem which is a question of dynamic memory allocation and
dynamic deallocation.
Here's a part of code to create database
include <iostream>
#include <string>
using namespace std;
struct subject {
string subname;
int score;
string grade;
float gpa;
};
struct student {
string stuname;
int stunum;
int subnum;
subject *sub;
float avegpa = 0;
};
int main(void){
int i = 0;
cout << "Put number of students : ";
cin >> i;
student* p = new student[i];
.
.
.
delete p->sub;
delete[] p;
return 0;
}
here's my desired result
Now, I have to enter the value of i first, but I hope I can automatically set
the value of i.
In order to try number 1, I pushed back value of i and increased i, but there was an
error. I don't know why.
This is the error message from number 2.
C++ crt detected that the application wrote to memory after end of heap buffer
delete p->sub;
You never initialised p[0].sub. Deleting (or even reading) an uninitialised pointer will result in undefined behaviour. You may delete only what you new.
P.S. Owning bare pointers are a bad idea. I recommend using std::vector to manage dynamic arrays.

C++ Declare array of unspecified length with string elements

What I'm trying to do here is quite simple. But some way, some how I'm missing something. I'm trying to "pre-declare" an array with strictly string elements in such a way that I can update the array contents during a specific period (periodically). So here are the snippets:
string ShotBox[] = {}; //"Pre-Declare" array that could contain as many elements here
Then I have a loop within my Update container. Snippet's:
for (int i = 0; i < sizeof(ShotBox) - 1; i++){
std::string soa = sPath;
std::string so = soa + ShotBox[i];
char *cstr = new char[so.length() + 1];
strcpy(cstr, so.c_str());
scPath = cstr;
}
All is fine with everything except the fact that whichever way I try to "pre-declare", I get a memory access violation. In this very exact snippets, the exact error is: an empty array is invalid for an array with unspecified bound.
I tried using "vector" but can't seem to work around it. What's the way to solve this? Please I don't want libraries. I need direct short methods or something of such.
Use std::vector<std::string>.
The vector manages an internal array.
std::vector<std::string> ShotBox; // (empty)
ShotBox.push_back(a_string); // add a string to the internal array
std::cout << ShotBox[0] << '\n'; // print first element
The problem of memory access violation itself is caused by your misunderstanding of sizeof operator. Specifically, sizeof(ShotBox) is the size (in bytes) of your array, not the ShotBox[] array size.
for (int i = 0; i < sizeof(ShotBox)/sizeof(std::string); i++) {
...
}
Inside the for loop ShotBox[] elements aren't updated at all. The only thing that happens is concatenation of sPath with ShotBox[i] into a new C string 'cstr'. If your aim is to update ShotBox[i] element, just add the following assignment to the end of for loop:
for (int i = 0; i < N_SHOT_BOX; i++) {
...
ShotBox[i] = so;
}
It's much more convenient to use std::vector for working with collections of variable size:
#include <string>
#include <vector>
#include <memory.h>
int main() {
std::vector<std::string> ShotBox{"str1", "str2", "str3"};
for (int i = 0; i < ShotBox.size(); i++){
std::string soa = sPath;
std::string so = soa + ShotBox[i];
char *cstr = new char[so.length() + 1];
strcpy(cstr, so.c_str());
ShotBox[i] = cstr;
}
return 0;
}
Galik's answer suggesting std::vector is the Modern C++ way to do what you want to do.
The reason your code doesn't work is that the following line of code doesn't do what you think it does
string ShotBox[] = {}; //"Pre-Declare" array that could contain as many elements here
Try adding the following to your program ...
std::cout << sizeof(ShotBox) << std::endl;
... and you should find that you've declared an array that is zero bytes long. Indeed some compilers will treat an empty initializer as an error if the array bounds are not specified.
In the C++ language arrays are fixed length entities. One way to approximate a dynamic array is to use a pointer and to use memory management functions to allocate a larger array and then copy the old array contents into the new larger array.
But that is a really bad idea.
Doing it correctly with exception safety and efficiency is hard to do and if you do manage it, you'll have re-implemented std::vector which seems like wasted effort!

No output and crash for simple program.What is wrong with my solution?

Problem-http://community.topcoder.com/stat?c=problem_statement&pm=12863&rd=15710
The program is not returning the required value even though the required values are being assigned to the variable 'output' which is being returned.The value being returned is probably a junk value.What is wrong with my solution?
My solution:
#include<iostream>
#include<vector>
using namespace std;
class ErasingCharacters
{
public:
string simulate(string s)
{
string output;
int i,j=0;
for(i=0;i<s.size()-1;i++) //2 simultaneous same characters are not omitted.
{
if(s[i]!=s[i+1])
{
output[j]=s[i];
j++;
}
else
i++;
}
int n;
n=s.size();
if(s[n-1]!=s[n-2]); //Including the last character(If it is not to be omitted.).
output[j]=s[n-1];
return output;
}
};
int main()
{
string input,output1;
ErasingCharacters o;
cin>>input;
output1=o.simulate(input);
cout<<endl<<output1;
}
The size of a default constructed std::string is 0. If you access an element of a std::string which is bigger or equal to the std::string's size you have undefined behavior. You should probably use std::string::push_back() to construct the result.
You didn't actually give your string any size.
Assigning characters to the string, without making the string big enough, is undefined. You're presently simply overwriting memory that isn't yours, as if you were accessing array elements out-of-bounds.
This is in contrast to languages like PHP which will automatically make room for them.
Instead of string[j] = s[i], use string.push_back(s[i]).
http://www.cplusplus.com/reference/string/string/push_back/

C++ why can you initialize an empty string array?

This is a "how does it work" question. Based on my understanding, you have to initialize a non-dynamic array with a constant number of elements (int intarr[5]) or your array will write over blocks of memory that might be allocated for something else.
So why is it that you can initialize a string array (string strArray[]) without any elements?
Example:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s[] = {"hi", "there"};
cout << s[0] << s[1];
cin >> s[10]; //why is this ok?
cout << s[10];
return 0;
}
As a feature C++ (and C) allows you to declare an array without specifying the number of elements if you specify an initializer for it. The compiler will infer the number of elements that's needed.
So for
int intarr[] = { 1,2,3,4,5};
The compiler will see that the array need to have room for 5 ints, and this is will be exactly the same as if you stated:
int intarr[5] = {1,2,3,4,5};
A string array is just the same;
string s[] = {"hi", "there"};
is the same as if you wrote
string s[2] = {"hi", "there"};
Your code has a serious bug though;
string s[] = {"hi", "there"};
cout << s[0] << s[1];
cin >> s[10]; //why is this ok?
cin >> s[10]; is absolutely NOT ok. The array s has only 2 elements, and even if the compiler does not generate an error, you cannot use s[10]
Doing so results in undefined behavior - so it could appear to work, or it could crash, or it could do anything.
You can use string strArray[] in 2 ways
string strArray[] = {"apple","banana"};
or
void function(string strArray[]) {
...
}
In the first case, the size of the array is automatically determined by the number of initializers (2). In the second case, the size of the array is not needed because it is a formal argument.
Other than that, you must declare a size to the array. It doesn't matter if it is based on string or int.
If you are writing to s[10] in your example but only have 2 elements, you are writing to unallocated memory and the program behavior is undefined. It may not crash, but later on something bad will happen.

How do I read a text file into an array of pointers? (C++)

What I need to do is read a text file into an array. Each line has four parts; first name, the ID, the height, and the weight. There are 13 lines in the text file, so I need to do it 13 times. I'm going to write a loop to make it work (and will be in a function I will parse the array to.) I know how to do it with a basic array, but we're supposed to use structs for this. I've looked around to try to find out how to do this, but nothing's really working for me. Here's the code I have so far.
#include <iostream>
#include <fstream>
#include <iomanip>
#include <string>
using namespace std;
struct person
{
string firstname;
int id;
double height;
double weight;
};
int main()
{
person array[13];
person *ptr;
ptr = &array[0];
ifstream inData;
inData.open("peeps.txt");
while(!inData.eof())
{
for(ptr = &array[0]; ptr < &array[13];ptr++)
{
inData >> person[ptr].firstname >> person[ptr].id
>> person[ptr].height >> person[ptr].weight;
}
}
}
The way you're doing it is fairly messy, but it's almost correct. Inside the for loop, you're trying to index person, which is a class. That doesn't make much sense. Instead, you have ptr which is pointing to each of the person objects in the array at each iteration, so you can just dereference it and assign to its members:
inData >> ptr->firstname >> ptr->id
>> ptr->height >> ptr->weight;
However, even worse, you have undefined behaviour in the for loop when you do array[13]. There is no element at index 13 so you can't attempt to access it like this. You could change the condition to ptr <= &array[12], but still, this is very messy.
To be clear though, you definitely don't have an array of pointers as you have said. Instead, you have an array of persons.
ptr = &array[0];
This takes the address of the first person in the array and assigns it to pointer. You can do this much more easily by taking advantage of array-to-pointer conversion:
ptr = array;
Also, eof() as your while criteria is often not a very good idea. It doesn't give a good indication of whether the next set of reads will succeed.