Strange behavior with getline C++ - c++

I am writing a simple program, where all the 'spaces' will be replaced by '%20'.
#include <iostream>
#include <string>
using namespace std;
int main (int argc, char* argv[]){
string input;
cout << "please enter the string where spaces will be replaced by '%20'" << endl;
getline(cin, input);
//count the number of spaces
int countSpaces = 0;
for (int i = 0 ; i < input.length() ; i++){
if (input[i] == ' '){
countSpaces++;
}
}
int size = input.length() + (2 * countSpaces) + 1;
//char cstr1[size];
char *cstr1 = new char[size];
char *cstr = cstr1;
for (int i = 0 ; i < input.length() ; i++){
if(input[i] == ' '){
*cstr++ = '%';
*cstr++ = '2';
*cstr++ = '0';
}
else{
*cstr++ = input[i];
}
}
*cstr == '\0';
cout << cstr1 << endl;
delete[] cstr1;
return 0;
}
I get the following strange behavior:
With the test input "this is strange " I get "this%20is%20strange%20%20his is" , where I just expect "this%20is%20strange%20%20"
If I hard code the same string, I get the correct results.
Replacing char *cstr1 = new char[size]; with char cstr1[size]; & removing the delete[] while still fetching the input via getline also removes the error.
I am using i686-apple-darwin10-g++-4.2.1:
Any help is much appreciated.

The last line must be *cstr = '\0'; not ==

Change the *cstr == '\0'; in the end of your code to *cstr = '\0';
ViolĂ !

*cstr == '\0';
this line checks if *cstr is equal to '\0' or not and return 1 or 0 accordingly
that is wrong as you want to insert the \0 character at the end of the string
so write single = instead of double =

Related

Buffer overload Error(C++ Visual Studios)

This is my code to read a file and store some lines from a position in the file and save it to an char array.
The code works fine , if i call getVNP() once in the main.
However when i try calling it the second time , I encounter a buffer overload error.
I tried searching , but I haven found a solution please help thanks.
#include <iostream> // library that contain basic input/output functions
#include <fstream> // library that contains file input/output functions
#include <string>
using namespace std;
void getVNP(std::string fileName, char* outStr)
{
int end;
int start;
char sWord[] = "Virtual";
char eWord[] = "[Default";
int position = 0; //this will be used incremental to fill characters in the array
int sWord_size = 0;
int eWord_size = 0;
//this loop is calculating the length of input word
for (int i = 0; sWord[i] != '\0'; i++)
{
sWord_size++;
}
for (int i = 0; eWord[i] != '\0'; i++)
{
eWord_size++;
}
fstream fin(fileName.c_str());
fin.seekg(0, fin.end);
int epos = fin.tellg();
fin.seekg(0, fin.beg);
cout << epos;
int array_size = epos; // define the size of character array
char * array = new char[array_size]; // allocating size an array
//opening an input stream for file test.txt
/*checking whether file could be opened or not. If file does not exist or don't have read permissions, file
stream could not be opened.*/
if (fin.is_open())
{
//file opened successfully so we are here
cout << "File Opened successfully!!!. Reading data from file into array" << endl;
//this loop run until end of file (eof) does not occur
while(!fin.eof() && position < array_size)
{
fin.get(array[position]); //reading one character from file to array
position++;
}
array[position - 1] = '\0'; //placing character array terminating character
//this loop is searching for the word in the array
for (int i = 0; array[i] != '\0'; i++)
{
for (int j = 0; sWord[j] != '\0' && j < 20 ; j++)
{
if (array[i] != sWord[j])
{
break;
}
else
{
i++;
if (sWord[j + 1] == '\0')
{
start = i-sWord_size+23;
}
}
}
}
for (int i = 0; array[i] != '\0'; i++)
{
for (int j = 0; eWord[j] != '\0' && j < 20 ; j++)
{
if (array[i] != eWord[j])
{
break;
}
else
{
i++;
if(eWord[j + 1] == '\0')
{
end = i-eWord_size - 11;
}
}
}
}
//take the start pos and the end pos text and put in string array s;
fin.seekg(start);
char *s = new char[end - start + 1];
fin.read(s, end - start);
s[end - start] = 0;
size_t len = strlen(s);
for(int i=0; i <len; ++i)
{
outStr[i] = s[i];
}
fin.close();
}
else //file could not be opened
{
cout << "File could not be opened." << endl;
}
getchar();
}
int main()
{
std::string FilePath;
std::string FilePath2;
char aConfig[] = " ";
char bConfig[] = " ";
std::cout << "Please enter a file path: ";
std::cin >> FilePath;
std::cout << "Please enter a second file path: ";
std::cin >> FilePath2;
getVNP(FilePath, aConfig);
cout << aConfig;
getVNP(FilePath2, bConfig);
cout << bConfig;
getchar();
return 0;
}
Your char aConfig[] is an array with 2 indices. The first one is the space and the second one \0 to indicate the end of the array.
If your path is longer than 1 letter, you should either dynamically allocate this, pass the function a std::string by reference, or use the MAX_PATH define (thought I recommend the std::string solution).
void getVNP(std::string fileName, std::string &outStr);
Also you should clean up if you allocate something with new. This is not java.
In main
char aConfig[] = " ";
creates array char[2] (space and null at the end). The second one (bConfig) creates another array char[2].
In getVNP
outStr[i] = s[i];
You are writing to this static array while you have only place for 2 characters.
Condider changing aConfig and bConfig to std::string or allocating bigger buffer (char aConfig[255];).

How to store adresses in an array - C++?

My Code example:
char* array = new char[10];
char* str;
int j = 0;
MyClass(char* input){ //input = sentence columns terminated by '\n'
str = new char[strlen(input)];
for(int i=0; i<strlen(input); i++){
if (input[i] == '\n'){ //look for end of line
str[i] = '\0'; //add \0 Terminator for char[]
array[j] = &(str[i]); //store address of sentence beginning in array
j++;
}
else{
str[i] = input[i];
}
}
}
How do i store an address into an array. So i can get the beginning address of a sentence by number. I created a solution with a vector storing my sentences as char* objects. But there must be a way without vectors?!
EDIT:
This is my solution.
#include <iostream>
using namespace std;
class Pointer{
public:
char** array = new char*[10];
char* str;
char* buffer;
int j = 1;
Pointer(char* input){
str = new char[strlen(input)];
array[0] = str;
for (int i = 0; i < strlen(input); i++){
if (input[i] == '\n'){
str[i] = '\0';
array[j] = &(str[i]) + sizeof(char);
j++;
}
else{
str[i] = input[i];
}
}
}
void output(int i){
buffer = array[i];
cout<<buffer;
}
};
Thanks for your help! :)
The best way would be to use std containers for that (std::vector<std::string>). Anyway, if you do need to have it the C way:
In this line:
array[j] = &(str[i]);
you are storing an address of ith character of the string. If you want to store the pointer to entire string, use:
array[j] = str;
Please note you have numerous other errors in your code.
For example, you should not be using a constant size array for that, as you're risking undefined behaviour in case you have more lines in your text.
Btw. MyClass is a function, not a class.
Answer to actual question:
char ** array = new (char *)[10];
What you should probably do instead:
std::vector<std::string> array;
char* array[10]
char* str;
int j = 0;
MyClass(char* input){ //input = sentence columns terminated by '\n'
str = new char[strlen(input)];
for(int i=0; i<strlen(input); i++){
if (input[i] == '\n'){ //look for end of line
str[i] = '\0'; //add \0 Terminator for char[]
array[j] = str; //store address of sentence beginning in array
// or you can use
// array[j] = &(str[0]);
j++;
}
else{
str[i] = input[i];
}
}
}
Hope it helps!
class Pointer{
public:
Pointer(std::string input){
addresses = split(input, '\n', addresses);
}
void output(int i){
std::cout << addresses.at(i);
}
private:
std::vector<std::string> addresses;
};

concatenating two strings c++

im trying to stick two strings together without using + operator,also using loops to to that.the problem is after when it read two strings it couldnt print the second string and only the first string appears.
here is my code
this code is like copying two strings in one.
char str1[MAX];
char str2[MAX];
cout<<"Enter The first String:\n";
cin.getline(str1,MAX,'\n');
cout<<"Enter the second String:\n";
cin.getline(str2,MAX,'\n');
char str3[2*MAX]; int k=0;
for(int i=0;i<MAX;i++)
{ str3[k]=str1[i]; k++; }
for(int j=0;j<MAX;j++)
{ str3[k]=str2[j]; k++; }
str3[k]='\0';
cout<<endl<<"Here is the concatenated string:\n";
cout<<str3<<endl;
It is better to write such code using pointers.
So I would substitute this wrong code
char str3[2*MAX]; int k=0;
for(int i=0;i<MAX;i++)
{ str3[k]=str1[i]; k++; }
for(int j=0;j<MAX;j++)
{ str3[k]=str2[j]; k++; }
str3[k]='\0';
for the following
char str3[2 * MAX];
char *p = str3;
char *q = str1;
while ( *p = *q++ ) ++p;
q = str2;
while ( *p++ = *q++ );
Also the same can be written using for loops. For example
char str3[2 * MAX];
char *p = str3;
for ( char *q = str1; *p = *q++; ++p );
for ( char *q = str2; *p++ = *q++; );
Your code goes past the end of str1 and str2, including their null terminators. Once the null terminator of srt1 is copied, C string inside str3 is considered complete, so str2 part is ignored.
You need to modify the first loop to stop once it sees '\0' in str1, and copy str2 from that point on. Do the same for the second loop. Your code adds null termination already, so the result will be correct:
for(int i=0;i<MAX && str1[i] != '\0';i++)
{ str3[k]=str1[i]; k++; }
for(int j=0;j<MAX && str2[j] != '\0';j++)
{ str3[k]=str2[j]; k++; }
Note: I am assuming that this is a learning exercise for which you are not allowed to use std::string.
Correct code should be:-
char str3[2*MAX];
int k=0;
for(int i = 0; str[i] != '\0'; i++)
{
str3[k]=str1[i];
k++;
}
for(int j=0 ; str2[j] != '\0'; j++ )
{
str3[k] = str2[j];
k++;
}
str3[k]='\0';
You were not taking into account null terminator and hence reading past that.
Change this :
for(int i=0; str1[i] ;i++)
{ str3[k]=str1[i]; k++; }
for(int j=0; str2[j] ;j++)
{ str3[k]=str2[j]; k++; }
You have to stop concatenating when str1 or str2 ends that is when str1[i] or str2[j]
will be 0 ('\0'). But you were looping through MAX. That's why your program produced wrong output.
Hope you understand now :)
#dasblinkenlight explains why this doesn't work in her/his answer.
Here's yet another solution using the standard C(++) library function strcat defined in . See http://www.cplusplus.com/reference/cstring/strcat/
#include <iostream>
#include <cstring>
using namespace std;
int main(int argc, char** argv) {
char str1[MAX];
char str2[MAX];
cout << "Enter The first String:" << endl;
cin.getline(str1, MAX);
cout << "Enter the second String:" << endl;
cin.getline(str2, MAX);
char str3[2 * MAX];
strcat(str3, str1);
strcat(str3, str2);
cout << endl << "Here is the concatenated string:" << endl
<< str3 << endl;
}

find and replace words in C++

I have a program to find and replace words in C++.
#include<iostream.h>
#include<string.h>
int main()
{
char string[80], replace[80], found[80], str1[80], str2[80], str3[80];
cout << "\nEnter string(max 3 words)\n";
cin.getline(string , 80);
cout << "\nEnter the word to be Found\n";
cin.getline(found , 80);
cout << "\nReplace with \n";
cin.getline(replace , 80);
for(int i = 0; string[i] != '\0'; i++)
{
str1[i] = string[i];
if(str1[i] == " ")
break;
}
for(int j = i; string[j] != '\0'; j++)
{
str2[j] = string[j];
if(str2[j] == " ")
break;
}
for(int k = j; string[k] != '\0'; k++)
{
str3[k] = string[k];
if(str3[k] == " ")
break;
}
cout << str1;
cout << str2;
cout << str3;
}
For this I stored every word as a different string, but it doesn't help.
What should be done to improve this?
Your code has too many logical & syntactical error.
Here is the modified code which will accept the required string and print expected output:
#include<iostream>
#include<string.h>
using namespace std;
void strreplace(string orgString, const string search, const string replace )
{
for( size_t pos = 0; ; pos += replace.length() )
{
pos = orgString.find( search, pos );
if( pos == string::npos )
break;
orgString.erase( pos, search.length() );
orgString.insert( pos, replace);
cout<<"String after replacement:"<<orgString<<endl;
}
}
int main()
{
char string[80], replace[80], found[80], str1[80], str2[80], str3[80] ;
cout << "\nEnter string(max 3 words)\n" ;
cin.getline(string , 80);
cout <<"\nEnter the word to be Found\n";
cin.getline(found , 80);
cout <<"\nReplace with \n" ;
cin.getline(replace , 80);
strreplace(string, found, replace);
return 0;
}
I hope this will help you.
In your current code you need to:
Use single quotes to compare characters for equality, not double quotes
Increment another index in your second and third loops. This is because the index for str2 and str3 needs to start at 0, not at the current position being looked at in string
Initalize the main string index (i) in second and third loops with (current value + 1) to skip past the space that it is currently at.
Null terminate your str1, str2, str3
1
if(str1[i] == " ")
should be
if(str1[i] == ' ')
2,3 Instead of
for(int j = i;string[j] != '\0' ; j++)
do
for (int j = 0, i = (i + 1); string[i] != '\0'; j++,i++)
The assignment becomes
str2[j] = string[i];
Do the same for the 3rd loop (without the int in front of j or use another letter). For consistency you could add a j variable starting at 0 to the first loop as well.
4 After each loop add an assignment statement for the null terminator (every c-string needs '\0' at the end to work properly) :
str1[i] = '\0';
str2[j] = '\0';
str3[j] = '\0';
std::string doesn't contain such function instead you could use stand-alone replace function from algorithm header.
#include <algorithm>
#include <string>
string stringReplace(std::string toSearch, std::string toReplace, std::string originalString) {
std::replace( originalString.begin(), originalString.end(), 'toSearch', 'toReplace'); // replace all 'toSearch' to 'toReplace'
return originalString;
}

Splitting char array

I have a char **names array that basically stores names from a file.
This is my .txt file
Mike, Sam, Stuart
Andre, Williams, Phillips
Patels, Khan, Smith
Basically, I want to split and store the names before the , character.
For example, Mike, Sam, Stuart will become...
newName[0] = Mike
newName[1] = Sam
newName[2] = Stuart
I have something like this...
for (int i=0; i<3; i++)
{
for (int j=60, j>0; j--)
{
if(names[i][j] == ',')
{
cout << j << endl; //THIS PRINTS OUT THE POSITION. HOW CAN I STORE THE POSITION AND DO SOMETHING?
}
}
}
I would appreciate it if someone could help me with my code, it is in the right direction. I don't want to use any vectors classes
I have attempted to store marks of these students, however I want to add it to a double *marks[2] array.
This is my .txt file...
69.9, 56.5
29.8, 20.0
35.6, 45.0
This is my code...
char **values;
char * pch;
pch = strtok (values[i], " ,");
while (pch != NULL)
{
sscanf(pch, "%f, %f", &marks[i][0], &marks[i][1]);
pch = strtok (NULL, " ,");
}
I am getting random values such as 1.28277e-307 and 1.96471e+257
look up the strtok command it will be very helpful to you.
This code looks for hyphen characters and prints stuff... change it to commas
#include <string.h>
#include <stdio.h>
int main()
{
const char str[80] = "This is - www.tutorialspoint.com - website";
const char s[2] = "-";
char * newName[100]; /* at most 100 names */
int iCurName = 0;
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL )
{
printf( " %s\n", token );
newName[iCurName] = malloc (char *) (strlen(token) + 1);
strcpy(newName[iCurName],token);
iCurrName ++;
token = strtok(NULL, s);
}
return(0);
}
Use function strtok() to split input line into tokens; use strcpy_s() to copy each token into name buffer.
Note 1: The strtok() function replaces each separator with '\0' character, so the line variable cannot be declared with const. If your input buffer must be constant, for example if you want to use the whole line for something else, make a copy of it before calling strtok() function.
Note 2: You might want to trim space in addition to splitting your input line.
#define MAX_LINE_LENGTH 80
#define MAX_NAME_LENGTH 20
#define MAX_NAMES_PER_LINE 3
const char constInput = "Mike, Sam, Stewart";
char line[MAX_LINE_LENGTH];
strcpy_s(line, MAX_LINE_LENGTH, constInput);
char *separator = ",";
char newName[MAX_NAMES_PER_LINE][MAX_NAME_LENGTH];
int i = 0;
char *token = strtok(line, separator);
while ((i < MAX_NAMES_PER_LINE) && ((token = strtok(NULL, separator)) != NULL))
{
strcpy_s(newName[i++], MAX_NAME_LENGTH, token);
}
char newName[3][60];
for (int i=0; i<3; i++){
int r=0, c=0;
for (int j=0; j<60; j++){
if(names[i][j] == ',' || names[i][j] == '\0'){
newName[r++][c] = '\0';
c = 0;
if(names[i][j] == '\0'){
cout << newName[0] << '\n'
<< newName[1] << '\n'
<< newName[2] << '\n' << endl;
break;
}
while(names[i][++j] == ' ')
;
--j;
} else {
newName[r][c++] = names[i][j];
}
}
}
#include <fstream>
#include <iostream>
using namespace std;
int main() {
ifstream inf("data.txt");
double marks[2];
char ch;
while(inf.good()){
inf >> marks[0] >> ch >> marks[1];
cout << "mark1:" << marks[0] << endl;
cout << "mark2:" << marks[1] << endl;
}
}
I don't know if this function works fast enough, but here it is:
char** split_quotes(char *input, char separator = ' ', bool keep_quotes = false)
{
if (&input && input)
{
size_t length = strlen(input);
char **chunks = new char*[length];
bool inQuotes = false;
size_t count = 0, from = 0;
for (size_t i = 0; i < length; i++)
{
if (input[i] == '"')
{
inQuotes = !inQuotes;
}
else if (input[i] == separator && !inQuotes)
{
size_t strlen = i - from;
if (strlen > 0)
{
if (!keep_quotes && input[from] == '"' && input[i - 1] == '"')
{
from++; strlen -= 2;
}
chunks[count] = new char[strlen + 1]();
strncpy(chunks[count], &input[from], strlen);
count++;
}
from = i + 1;
}
}
if (from < length)
{
size_t strlen = length - from;
if (!keep_quotes && input[from] == L'"' && input[length - 1] == L'"')
{
from++; strlen -= 2;
}
chunks[count] = new char[strlen + 1]();
strncpy(chunks[count], &input[from], strlen);
count++;
}
// Save chunks to result array //
char **result = new char*[count + 1]();
memcpy(result, chunks, sizeof(char*) * count);
// free chunks //
delete[] chunks;
return result;
}
return NULL;
}
Usage:
wchar_t **name = split_quotes(L"Mike,Donald,\"My Angel\",Anna", L',');
if (name)
{
while (*name++)
{
std::wcout << "Person: " << *name << std::endl;
}
}