So I need to turn a c-string of characters (letters and spaces) into a 2-dimensional array of c-strings. Each "row" of the 2D array must consist of letters and only letters. Essentially I need to take the words of a sentence and make an array out of them.
For example: "im upset that on nov th my brandnew bmw lis were stolen" should be turned into 2d c-string array like: "im","upset","that","on","nov","th","my","brandnew","bmw","lis","were","stolen".
(Notice that there are two space characters between "th" and "my" & "my" and "brandnew")
The following code gives me some interesting output in my console...
char document[201] = "im upset that on nov th my brandnew bmw lis were stolen";
char documentArray[13][201];
for (int i, k, j = 0;document[k] != '\0';)
{
if (isspace(document[k]))
{
cout << "found a space" << endl;
k++;
while (isspace(document[k]))
{
k++;
}
i++;
j = 0;
}
if (isalpha(document[k]))
{
documentArray[i][j] = document[k];
k++;
j++;
}
}
for (int i = 0; i < maxWords +1; i++)
{
cout << documentArray[i] << endl;
}
The output produced has some weird stuff in it. I don't know what it means (if you could tell me that would be awesome). Could you please help me solve this issue?
Here's the console output:
im\203\377
upset
that
on
nov
th
my\3261
brandnew
bmw_\377
lis
were
stolen\301$r\377
\377
after the line with the j++; insert the following
if (j < 201) {
documentArray[i][j+1] = '\0'; # terminate the c string
} else {
documentArray[i][j] = '\0'; # cannot terminate the c string, overwrite the last char to terminate the string
}
But please make sure that every read AND write operation NEVER exceeds the array dimensions.
Your array limits are documentArray[0..12][0..200].
Please ALWAYS check that. => http://en.wikipedia.org/wiki/Buffer_overflow
Try adding a terminating null character to the end of your C strings when copying into the 2D array.
In C string are represented by arrays of characters terminated by a '\0' character. The strange codes you are seeing are likely the result of the '\0' not being encountered and the print running of the end of the character array.
Related
I'm a beginner in C++ and programming itself actually. I just want to ask, What's the difference between these 2 examples. What is the difference between "len = strlen(str1)-1" and "i = strlen(str1)-1"
Top part of the code will be like this:
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char str1[20],str2[20];
int c, i ,j, len;
cout<<"Enter a word: ";
cin.getline(str1, 20);
Example 1:
//reverse
for (i = strlen(str1)-1, j = 0; i >= 0; i--, j++){
str2[j] = str1[i];
}
//compare string
c = strcmp(str1, str2);
/*This does not work because the value of 'c' will be -1 if the input
is "lol" which is palindrome*/
and Example 2:
//reverse
len = strlen(str1)-1;
for (i = len, j = 0; i >= 0; i--, j++){
str2[j] = str1[i];
}
//compare string
c = strcmp(str1, str2);
/*This does work in other hand, because of the variable "len"*/
the rest of the code will be like this
if(c == 0){
cout<<"It is a Palindrome";
}
//if the value of C is !=0
else{
cout<<"It is not a Palindrome";
}
}
Why is that? Thanks in advance for those who will answer. :)
Both examples are same except first uses an extra variable len.
This code is actually reversing the string. If str1 contains "123" then str2 will contain "321".
Function strlen(str1) returns the length of str1 but in C++ index of Arrays start from 0 that is why the last element index will be one less than length, hence strlen(str1) - 1.
UPDATE
Even with updated information the answer to first question remains same that both examples are same in nature. Difference in results is a mare co-incident due to a reason explained below.
char str1[20],str2[20];
This code creates two array of 20 char but not initialized. This means the initial values can be random.
Now when you call cin.getline(str1, 20); it not only writes the string you entered but adds a terminating '\0' character at the end of it. Our reversing logic only reverse the string but does not insert terminating '\0' at the end of str2 which means str2 is much longer (until it finds a '\0') than str1. Due to this they never compare correctly.
A simple solution to this issue can be zero-filling the arrays before using them and in C++ there is a simple way to do that:
char str1[20] = { 0 }, str2[20] = { 0 };
It is always a good practice to zero-fill your arrays if you are going to use then as strings.
I'm trying to read a column of names from a text file into a two dimensional array, the names vary in length but are at max 8 letters long, and there are 10 of them. Here are my two for loops to read the names and then to print them.
for (int i = 0; i != 10; i++) {
for (int j = 0; j != 8; j++) {
infile >> textfileinfo[i][j];
}
}
and then to print the names out I have this loop.
for (int i = 0; i != 10; i++) {
for (int j = 0; j != 8; j++) {
cout << textfileinfo[i][j];
}
cout << " " << endl;
}
Here is the list of names:
Victor
Eve
Juliet
Hector
Danielle
Romeo
Oscar
June
Ares
Dannae
What ends up happening is it will read the names out with 8 characters regardless, taking the extra characters from the next name, so Victor turns into VictorEv, then eJulietH and so on. How do I get it to start on the next row once the end of Victor is reached, and then move on to Eve etc. I am not allowed to use pointers either. Any help is appreciated! Thanks.
Seems the obvious thing is to use getline. getline is designed to read a single line of text.
for (int i = 0; i != 10; i++) {
infile.getline(textfileinfo[i], 9);
}
Note that the second argument to getline is 9 because you need an extra character to store the nul terminator that ends every C style string. This also mean that your 2D array need to be declared with at least 9 characters in each row. Slightly safer code would be to make this explicit
infile.getline(textfileinfo[i], sizeof textfileinfo[i]);
If for some reason you aren't allowed to use getline then you going to have to modify your inner loop to detect and deal with the '\n' character that terminates every line.
So I want to create 1000 words with a length of 5 random characters. In my main I have word[1000] but when I try to run this code, it gives me an error saying "Expression:string subscript out of range". I'm not sure why it does that because I thought string arrays were 2 dimensional? If anyone could tell me why my code is wrong I'd appreciate it. Thanks.
void createText(string w[], int seed) {
char ch;
srand(seed);
for(int i = 0; i < 1000; i++) {
for(int j = 0; j < 5; j++) {
ch = ('A' + rand() % 26);
w[i][j] = ch;
}
}
for(int i = 0; i < 1000; i++) {
cout << w[i];
}
cout << endl;
}
I suppose that the array w does not have 1000 elements, also remember that here you will get a copy of string w[]. Better would be passing a pointer to w (string* w), then You will have very clearly what is wrong. remember also that cout writes the string out untill it reaches a '\0' character, this also might be the cause. Quick session with gdb will help:
gdb program
...
run
bt full
should pinpoint Your problem. if it's some kind of IDE, learn how to debug in it. Valgrind or some other memcheck like visual leak detector or luke stackwalker will also show you some tips about bad initialization or unmentioned memory leaks.
If an array is bidimensional, you can't print its values like w[i]. You must print always keeping in mind that the array is bidimensional, which means that the output must be done like cout << w[i][j];
In addition, you're passing an array of strings as an argument, and what you're doing is add characters to every single position, which means that you won't actually have nothing but 1000 characters inserted into that string (because you actually added "one-char" strings), so you'll only put 200 words with a length of 5 characters each one. Insert strings directly, and you'll get your 1000 words, but first find a way to build strings with random characters.
Something like:
for(conditions){
for(conditions){
build a word
}
array[x][y] = string
}
I guess it is similar to what you intended to do
I'm attempting to write alil function here which basically reads from a string. It reads every three characters and evaluates it using the pre-condition (if statement). If conditions are met, it would replace those three letters with new three letters. Then it would output the new string.
I tried writing the code but cant seem to get the logic right. the program runs but it doesn't print out anything. Dont mind the function name and the inaccuracy. I'm just doing a sample function to test this out.
string amino_acids(string line)
{
string acid;
string acids;
string newline;
for( int i= 0; i < line.length(); i++)
{
acid = line[i];
}
for (int i = 0; i < 3; i++)
{
acids = acid[i];
if(acids == "GUU")
{
acids = "ZAP";
}
newline = acids;
}
cout << "Acids: " <<newline <<endl;
return newline;
}
for( int i= 0; i < line.length(); i++)
acid = line[i];
Say line contains "abcd", this loop is going to do:
acid = 'a';
acid = 'b';
acid = 'c';
acid = 'd';
Only the last assignment has any lasting affect. If you need to actually get three characters from line into acid - you probably want to use += to add characters into acid, rather than =. But, if you loop over all of line like this, you'll end up doing acid = line;. I assume you want something more like acid = line.substr(0, 3)?
for (int i = 0; i < 3; i++)
{
acids = acid[i];
This is going to crash. acid is definitely a single character string, and you're indexing into acid[1] and acid[2] on the 2nd and 3rd iterations. While you're learning C++, you should probably use .at(i) which will throw an exception when you attempt to use an invalid index - you can catch the exception and at least have some indication of the problem. As is, it's undefined behaviour.
To use at, you need a try / catch block... the basic form is:
int main()
try
{
...your code in here...
some_string.at(i);
}
catch (const std::exception& e)
{
std::cerr << "caught exception: " << e.what() << '\n';
}
More generally, try putting some std::cout statements throughout your code so you know what values your variables actually have... you would easily have seen that they weren't what you expected. Alternatively, use an interactive debugger and watch the affect of each statement's execution.
Indexing a std::string with the [] operator yields a char, for which there just happens to be an overloaded operator= for strings.
Even if you were looping as I believe you intended (which, as the comments on the question mention, you probably aren't) because acids (which takes the value of a single character) will never be equal to the three character string you're comparing it to. Thus, no replacements will be performed.
To do what you want, try something like this:
for (int i = 0; i + 3 < line.length(); i += 3) // counting by 3 until end of line
{
if (line.substr(i, 3) == "GUU") // if the substring matches
{
line.assign("ZAP", i, 3); // overwrite it with new substring
}
}
return line;
Reading from your description, you want something like so
//note below does not compile, its just psuedo-code
string amino_acid(const string& sequence){
string result = sequence; //make copy of original sequence
For i = 0 to sequence.length - 3
string next3Seq = sequence(i,3); //grab next 3 character from current index
If next3Seq == 'GUU' //if the next next three sequence is 'GUU'
then result.replace(i,3,'ZAP'); //replace 'GUU' with 'ZAP'
EndIf
EndFor
return result;
}
You can use that as a start to code. Good Luck.
According to my understanding of your question. I have written some code. Please look below
string acids;
string newLine;
int limit=1;
for(int i=0;i<line.length();i++)
{
acids=acids+line[i];
if(limit==3)//Every 3 characters
{
if(acids == "GUU")
{
acids = "ZAP";
}
limit=1;
acids=""
newline=newline+acids;
}
limit++;
return newline;
}
I am making a Sudoku program and my i have a test.txt file that reads
53__7____
6__195___
_98____6_
8___6___3
4__8_3__1
7___2___6
_6____28_
___419__5
____8__79
where the "_" are actually spaces. The reason i give you _ is so you can see that there are literally only 9 characters on each line.
I was thinking that I would have to do something like having GRID[row][column], however I frankly don't know what types I should put my arrays as and I am just lost.
I simply want to make it so when i want to output say GRID[0][0] it returns 5, while if i ask for GRID[0][3] it returns a ' '.
It is getting it so the array store both the numbers and the spaces is where i am getting completely lost
What I currently have tried so far:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.is_open())
{
while(myfile.good())
{
getline(myfile, line);
cout << sudoku_grid[line] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
it returns the error line 12: no match for 'operator [ ]' in 'sudoku_grid[line]'
Here is my attempt though guidelines through you guys:
int main()
{
ifstream myfile(test.txt);
string line;
char sudoku_grid[9][9];
if (myfile.good())
{
for(int i = 0; i < 9; i++)
{
getline(myfile, line);
for(int j = 0; j < 9; j++)
{
if (line[j] == ' ')
sudoku_grid[j][i] = -1;
else sudoku_grid[j][i] = line[i];
}
cout << sudoku_grid[i] << endl;
}
myfile.close();
}
else cout << "error";
return 0;
}
The result is a very awkward answer of strange letters and a new numbers.
I'll just give you the algorithm/logic, not going to write the code for you. Try it and come back when stuck.
Initialize output in memory 2D array: numbers[9][9]
Open the file
Until there is no line left in the file:
a. Get the line i
b. Until there are no more characters in the line:
b1. Get each character of the line c
b2. If the character is not space, then numbers[i]=c, else numbers[i]=-1
Your array can be made up of int and in b2 if a whitespace is encountered you can insert -1 to indicate the absence of a number. Of course your code manipulating numbers array needs to take that into account.
Since you need to store both chars and integer type values, use char. each of your integer lies in the range 0-9, so can be stored as a character.
char Grid[9][9];
now you can read each character from the string and store it in the array. It will not only keep your spaces intact but also each character. Always remember to use ASCII codes to access the elements of the grid. For 0-9, ASCII codes are 48-57, ASCII code for space is 32.
Hope it helps...
Edit code: Here is the simplest example... PLace your test file in d:, or edit the path of file in code
int main (void)
{
FILE *fp = fopen("d:\\test.txt","r");
char sudoku_grid[9][9], ch;
// I am assuming that file is valid and data in that is also valid
if(fp)
{
for(int i = 0; i < 9; i++)
{
for(int j = 0; j < 9; j++)
{
//too read each character
ch = fgetc(fp);
sudoku_grid[i][j] = ch;
}
// to read '\n' from the line
ch = fgetc(fp);
}
//for checking if data went correctly
for(int i = 0; i< 9;i++)
{
for(int j= 0; j<9;j++)
cout<<sudoku_grid[i][j];
cout<<endl;
}
}
return 0;
}
In the first code you get the error message because sudoku_grid can
only be indexed by numbers and not by strings.
In the second code the line
sudoku_grid[j][i] = line[i];
should probably be
sudoku_grid[j][i] = line[j];
Does this answer your question?