storing a string to a 2d char array - c++

I am trying to store a sentence to a 2d array by separating each words. In the 2d array each row will contain each word from the sentence. Here is what I think I should do.
//Logic
//given string mystring
string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char 2darr[4][10] = {" "};
int x = 0;
for (int i = 0,j=0; i <mystring.length(); i++)
{
if (mystring(i) != ' ')
2darr[x][j++] = mystring(i); //copy the each character to the first row
else
2darr[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
Is there a better way to do this? I think my logic is a little off as well

The better way to do this is:
1) There is no need to check spaces. For this to occur, you can use std::istringstream with operator >> to obtain each word in a loop.
2) Use strncpy to copy the string into the 2 dimensional array
3) You need to make sure that the string does not exceed the bounds of the array, and that you have no more than 4 separate words.
Here is an example:
#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <cstring>
int main()
{
char arr2d[4][10] = {};
std::string mystring = "testing the arrays";
// create an input stream containing the test string
std::istringstream strm(mystring);
std::string word;
// this is the word count
int curCount = 0;
// obtain each word and copy to the array
while (strm >> word && curCount < 4)
strncpy(arr2d[curCount++], word.c_str(), 9);
// output the results
for (int i = 0; i < curCount; ++i)
std::cout << arr2d[i] << "\n";
}
Output:
testing
the
arrays

this expression char 2darr[4][10] = {" "} will only set the first element to be " ", the others will be '\0' or NULL. But it is probably OK, since it is the default terminator of C-strings.
Variables can't start with a digit, call it arr2d instead.
String character access is mystring[i], not mystring(i)
You only indented the lines in the else block, in C++ if you don't enclose a block with curly braces, it only captures the first row, what you basically wrote is:
else {
2darr[x][j++] = '\0';
}
++x; // goes to next row
j = 0; //reset j for new row
Corrected code is
std::string mystring = "testing the arrays";
//create a 2d char array to hold 4 words with 10 max size
char arr2d[4][10] = { };
int x = 0;
for (int i = 0, j = 0; i < mystring.length(); i++)
{
if (mystring[i] != ' ') {
arr2d[x][j++] = mystring[i]; //copy the each character to the first row
}
else {
arr2d[x][j++] = '\0';
++x; // goes to next row
j = 0; //reset j for new row
}
}

Related

Can I store a string in character array but reverse order, such that 0(index) points to last character in string?

I started to learn to program and I'm trying to store a string into a character array but in reverse order, such that array index position 0(zero) points to the last character in the string. I tried using for loops in different terms but getting the desired output. I want to solve this problem in C++.
Here is the code that I'm stuck on,
#include <iostream>
using namespace std;
int main()
{
char str[maxn];
string entstr;
cin>>entstr;
int len = entstr.length();
cout<<len<<endl;
for(int i = 0 ; i < len ; i++) //this makes \n no sense//
for(int j = len-1 ; j >= 0 ; j--)
str[i] = entstr[j];
for(int i = len-1 ; i >= 0 ; i--)
cout<<"Straight for array "<<i<<" "<<str[i]<<endl;
return 0;
}
OUTPUT:
sachin
6
Straight for array 5 s
Straight for array 4 s
Straight for array 3 s
Straight for array 2 s
Straight for array 1 s
Straight for array 0 s
I guess you don't wanna use std::reverse mentioned in the comments because you want to practice your algorithmic skills.
You can help yourself with this short program. It uses std::malloc to allocate a char array of the size of the input string. Then, you just need to loop backward through the character of the string and store it into your array.
I recommend you to follow (write it down on a paper) the values of i and len-1-i inside the loop. It will help you to understand how index works.
#include <iostream>
using namespace std;
int main()
{
string entstr;
cin >> entstr;
int len = entstr.length();
char* charArray = (char*) malloc (len);
for(int i = 0; i < len; i++)
{
charArray[i] = entstr[len-1-i];
}
cout << "charArray contains: ";
for(int j = 0; j < len; j++)
{
cout << charArray[j];
}
return 0;
}
Good luck!
I don't think there is any use for two loops. Just start the string from the front and your array from len-1 (just the way you did in the for loop for printing). You can take whatever length you want your char array to be.
#include <iostream>
using namespace std;
int main()
{
char str[100]; //put whatever you want the length of the char array to be
string entstr;
cin>>entstr;
int len = entstr.length();
cout<<len<<endl;
for(int i = 0 ; i < len ; i++)
{
str[len-1-i]=entstr[i];
}
for(int i = len-1 ; i >= 0 ; i--)
cout<<"Straight for array "<<i<<" "<<str[i]<<endl;
return 0;
}
You can use two pointers too for the same i.e. one starting from the front and one from the end (if you get confused)
for(int i = 0, j=len-1 ; i < len ; i++, j--)
{
str[j]=entstr[i];
}

Splitting function in C++

I am trying to write a function that takes a string and a delimiter as an input and return an array of strings. For some reason, the following code runs into segmentation error. I am wondering what could be the problem?
char** split(string thing, char delimiter){
thing+='\0';//add null to signal end of string
char**split_string = new char*[100];
int i=0,j=0,l=0; //indexes- i is the ith letter in the string
// j is the jth letter in the lth string of the new array
int length = thing.length();
while (i < length){
if ((thing[i]!=delimiter && thing[i]!='\0')){
split_string[l][j]=thing[i];
j++;
}
else {
j=0; //reset j-value
l++;
}
i++;
}
return split_string;
}
After doing
char**split_string = new char*[100];
You still need to initialize each of the 100 char * pointers you created.
static const size_t str_len = 50; //assuming length will not exceed
for( size_t ix = 0 ; ix < 100 ; ++ix){
split_string[ix] = new char[str_len];
}
Also you need to make sure while writing to split_string you do not exceed the allocated memory in which case its 50 and you don't have splited strings more then 100.
Better split a std::string to std::vector<std::string>. Use the function below
#include <sstream>
#include <string>
#include <vector>
std::vector<std::string> split(std::string str, char delim) {
std::vector<std::string> result;
std::stringstream ss(str);
std::string token;
while (getline(ss, token, delim))
result.push_back(token);
return result;
}
1) Please allocate memory for each substring (something like char[l] = new char[100]) when ever you find a new substring.
As you do not know the number of substring in the beginning itself, please consider using vector. consider using vector < string > split_string. In the loop when ever you find a new sub string you just push that string in the vector. In the end, you will have all the splitted strings in the vector.
Each char * has to be individually initialized like this.
int len = 100;
char**split_string = new char*[len]; // len holds the number of pointers
for(int k = 0; k < len; k++) {
split_string[k] = new char[500]; // holds len of string (here Max word size is considered 500)
}
In C++, sticking to the usage of std::string would be more recommended to reduce complexity and increase readablity.
Your code will fail to catch hold of the last substring as you are breaking out of while-loop just before finding \0. To fix that you need to change the while (i < length) to while (i <= length).
Using vector < string >:
vector<string> split(string thing, char delimiter){
int len = 100;
vector<string> v;
char c[500];
int i=0,j=0;
int length = thing.length();
while (i <= length){
if ( thing[i] != delimiter && thing[i] != '\0') {
c[j]=thing[i];
j++;
}
else {
c[j] = '\0';
v.push_back(c);
memset(c, 0, sizeof c);
j = 0;
}
i++;
}
return v;
}
Demo.

Trouble with a Pointer to an Array of Structures in C++

My assignment is to translate a phrase from pig Latin to English using a structure. My project thus far takes in a string, removes all capitalization, all punctuation besides the ending punctuation, and splits the string into an array of structures comprised of words. I am then supposed to, through the return statement specifically, return a pointer to my array of structures. When back in main, I want to create another array of structures identical to that in my pigLat function that I will be able to send to a new function for the second part of my project (which will consist of translating the pig latin to english).
The problem: trying to create a new array using the pointer causes a core segmentation fault.
Any help explaining why this doesn't work, and explaining what might work better would be appreciated!
#include <iostream>
#include <string>
#include <algorithm>
#include <cctype>
using namespace std;
struct Word //Variable type to hold each word
{
string piglatin;
string english;
};
Word *pigLat(int &);
int main()
{
int size;
Word *phrase;
phrase = pigLat(size); //Passes value of size by reference, and returns ptr to structure
Word pigSent[size];
//THIS IS WHERE I GET SEGMENTATION FAULT************************************
for (int count = 0; count < size; count++)
{
pigSent[count].piglatin = phrase[count].piglatin;
}
//*************************************************************************
return 0;
}
//Receives a phrase in pig latin, finds # of words in phrase, seperates pig latin from english, returns pig latin
Word *pigLat(int &sizeOf)
{
string phrase; //Variable to hold pig latin phrase
cout << "Enter a phrase in pig latin: "; //User enters pig latin phrase
getline(cin, phrase);
char punctuation = phrase[phrase.length() - 1]; //Assumes last char is punctuation, and saves it
//Removes all characters besides last period
char removch[] = "&,'?.!-";
for (int count = 0; count < 7; count++)
{
phrase.erase(remove(phrase.begin(), phrase.end(), removch[count]), phrase.end());
}
int length = phrase.length(); //Number of elements in updated string
phrase.insert(length, 1, punctuation); //Inserts final punctuation at end of phrase
//Removes all capitalization
for (int count = 0; count < length; count++)
{
if(phrase[count] >= 'A' && phrase[count] <= 'Z')
{
phrase[count] = tolower(phrase[count]);
}
}
int index = 0;
int count = 0;
int *spaceElements = 0;
spaceElements = new int[length]; //Dynamically allocates spaceElements memory
for (count; count < length; count++) //Gives number of white spaces in phrase
{
if (phrase.find(' ', count) != -1)
{
int space = phrase.find(' ', count);
count = space;
spaceElements[index] = space;
index++;
}
}
sizeOf = (index + 1);
Word sentence[sizeOf];
int start = 0;
int end = 0;
count = 0;
//Copies, word by word, into Word array sentence
for (count; count < sizeOf; count++)
{
for (count; count < index; count++)
{
end = spaceElements[count] - start;
sentence[count].piglatin = phrase.substr(start, end);
start = spaceElements[count] + 1;
}
sentence[count].piglatin = phrase.substr(start, length);
}
//Testing***************************************************
for (count = 0; count < sizeOf; count++)
cout << endl << sentence[count].piglatin << endl;
//**********************************************************
delete [] spaceElements;
Word *ptrToSet = sentence; //assigns pointer to memory address of sentence array
return ptrToSet;
}
The pigLat() function instantiates sentence in the local function scope:
Word sentence[sizeOf];
PigLat() returns a pointer to the first element of this array:
Word *ptrToSet = sentence;
return ptrToSet;
However, once pigLat() returns, because sentence was a locally-scoped object, it goes out of scope and gets destroyed. Subsequent attempts to dereference the returned pointer is undefined behavior. This is the likely reason for your application crash. There may be other reasons too, I didn't look any further.

How to read integers from file into dynamic array

I am trying to read integers from a text file and put them into a dynamic array that will be represented as vectors and matrices for an assigment.
An example of a few lines from the input file:
3#456
33#123456789
The numbers before the pound sign represent the elements of the vector or matrix, so 3# would mean a three element vector and 33# would mean a matrix with 3 rows and 3 columns.
Reading those isn't really a problem as we were told we can assume we know which lines are matrices and which are vectors, however, I have never working with C++ file I/O so I don't know how to iterate through the numbers 4,5,6 and put them into a 3, 9, 12, etc, element dynamically created array. Here's somewhat of a sample of what I'm working with.
int *a;
int size_a;
char x;
ifstream infile("input.txt");
if (infile.is_open())
{
infile >> size_a;
// The x is basically a junk variable used to go past the '#'
// when reading the file
infile >> x;
a = new int[size_a];
}
After that, I have no real idea of how to loop until the end of the line and put the remaining elements in the array. For example in this line, the numbers 4, 5, and 6 would need to be put into the a array, then break from adding elements and go to the next line to work on the next array, which I don't know how to do either. Any ideas?
The below code will do this for you. Note that you do not need to use new here - you should just use a std::vector. In that case, the number before the '#' is unneeded as you do not need to specify the size of the array when you create it.
For that reason I have used new here anyway to show you how to read both parts of the file.
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream file("input.txt");
if(file.good()) {
std::string line;
std::getline(file, line);
std::string::size_type pos = line.find('#');
std::string strSize = line.substr(0, pos);
std::string strValues = line.substr(pos + 1);
int size = 0;
for(char c : strSize) {
if(size == 0)
size = static_cast<int>(c - '0');
else
size *= static_cast<int>(c - '0');
}
int* values = new int[size];
for(int i = 0; i < size; ++i) {
values[i] = static_cast<int>(strValues[i] - '0');
}
std::cout << "Array of size " << size << " has the following values:" << std::endl;
for(int i = 0; i < size; ++i) {
std::cout << values[i] << std::endl;
}
delete[] values;
}
}

C++: Printing/assigning simple array prints gibberish

My code basically is to list ASCII codepoints of a string that is input, my following code is simple, here:
#include <iostream>
#include <string.h>
using namespace std;
int main() {
char str[20];
int result[20];
cin >> str;
for(int i = 0; i != strlen(str); i++) {
result[i] = (int)i;
}
for(int i = 0; i != 20; i++)
cout << result[i] << ", ";
}
when I run it, no matter what the input it outputs a pile of gibberish like undefined memory like so:
0, 1, 2, 3, 4, 5, 1, -1217349408, -1220040795, -1220041307, -1076427112, 134514781, -1218903292, 134519344, -1076427096, 134514004, -1217411568, 134519344, -1076427048, 134514681,
Am I missing something simple in how I append each integer to the array?
Just note this is a simple example, my input will not be larger than 20 characters.
EDIT Typo in my result.. cin>>result was cin>>str
This loop will iterate a number of times equal to the length of 'str'. That is, it will iterate once for each character in 'str', and stop at the 'null terminator' (char value of 0) which is how c strings are ended. In each loop, the value of 'i' is the loop number, starting at 0 - and this is the value you assign to that index in the results array.
for(int i = 0; i != strlen(str); i++) {
result[i] = (int)i;
}
So for example, for a string of length 5, you will assign the values '0, 1, 2 ,3, 4' to the result array at those indexes, respectively. The other values in the result array are not assigned - and so could hold any value (generally, whatever was in that bit of memory before you started using it). If your string is longer than 20 characters, you're in trouble, because you will start trying to access the array at index 20 and beyond, which is not memory that belongs to your program.
This loop prints out all the values in the 'result' array, from the value at index 0 to the value at index 19:
for(int i = 0; i != 20; i++)
cout << result[i] << ", ";
So it will print the initialised values, and, if the string was less than 20 characters long, the uninitialised values as well.
At a minimum, to start getting anything like the results you're after, you want to change
result[i] = (int)i;
to
result[i] = str[i];
but as mentioned by others, and to escape some of the memory access issues I mentioned above, it would be much better if you use an iterator to get the character values.
for(string::iterator i = str.begin(); i != str.end(); i++)
// access char here using '*i'
strlen(str) will give you an undefined output, because you haven't initialised the contents of str[].
Essentially, you failed to correctly initialize the string and you didn't check that it was the correct size. Correct code:
#include <iostream>
#include <string> // NOT <string.h>, <string>
int main() {
std::string str;
std::cin >> str;
std::cin.ignore();
for(std::string::iterator it = str.begin(); it != str.end(); it++) {
std::cout << (int)(*it);
if (it + 1 != str.end())
std::cout << ", ";
else
std::cout << "\n";
}
std::cin.get();
}
You have 3 problems:
You didn't initialise str with a proper string, thus strlen will return an unpredictable value.
You initialise the first strlen(str) positions of result, but later you print it until the index 20. You should use the same condition on both loops.
You should definitely use std::string and its iterator.
You've not initialized str and you are taking its strlen
When you did
cin >> result; // this does not even compile!!!
I guess you meant
cin >> str;
Its not clear what you are trying to do. But you can try this to get some meaningful result:
char str[20];
int result[20] = {0};
cin >> str;
...// rest all unchanged.
stlen( str ) will give the number of characters before the null terminator.
This means that only strlen(str) integers are valid. The rest are uninitialized.
Also: have a look at std::transform. You can avoid the temporary array of integers to achieve the same, or transform right into one.
int to_codepoint( char c ) { return (int) c; }
// ...
char cs[] = "abcd";
std::transform( cs, cs+strlen(cs)
, std::ostream_iterator<int>( std::cout, ", " ), to_codepoint);
// or transform into an array:
int is[ 1000 ]; // 1000 enough?
std::transform( cs, cs+strlen(cs)
, is, to_codepoint );
(test code at codepad.org)