I'm new to C and C++ programming, can anyone give me a hint on what I'm doing wrong here. I'm trying to write to concat function that takes to pointers to chars and concatenates the second to the first. The code does do that, but the problem is that it adds a bunch of junk at the end. For instance, when passing the arguments - "green" and "blue", the output will be "greenblue" plus a bunch of random characters. I also wrote the strlen function that strcat uses, which I will provide below it for reference. I'm using the online compiler at https://www.onlinegdb.com/online_c++_compiler
The exact instructions and specification is this:
The strcat(char *__s1, const char *__s2) functions concatenates the contents of __s2 onto __s1 beginning with the NULL character of __s1. Note: The concatenation includes the NULL character of __s2. The function returns __s1.
int main(int argc, char** argv)
{
const int MAX = 100;
char s1[MAX];
char s2[MAX];
cout << "Enter your first string up to 99 characters. ";
cin.getline(s1, sizeof(s1));
int size_s1 = strlen(s1);
cout << "Length of first string is " << size_s1 << "\n";
cout << "Enter your second string up to 99 characters. ";
cin.getline(s2, sizeof(s2));
int size_s2 = strlen(s2);
cout << "Length of second string is " << size_s2 << "\n";
cout << " Now the first string will be concatenated with the second
string ";
char* a = strcat(s1,s2);
for(int i = 0; i<MAX; i++)
cout <<a[i];
// system("pause");
return 0;
}
//strcat function to contatenate two strings
char* strcat(char *__s1, const char *__s2)
{
int indexOfs1 = strlen(__s1);
int s2L = strlen(__s2);
cout <<s2L << "\n";
int indexOfs2 = 0;
do{
__s1[indexOfs1] = __s2[indexOfs2];
indexOfs1++;
indexOfs2++;
}while(indexOfs2 < s2L);
return __s1;
}
//Returns length of char array
size_t strlen(const char *__s)
{
int count = 0;
int i;
for (i = 0; __s[i] != '\0'; i++)
count++;
return (count) / sizeof(__s[0]);
}
The behavior you are seeing is a result of the null terminator of __s1 being overwritten by data from __s2 and no new null terminator being appended. The extra characters you are seeing are just random values in RAM that happen to be after the end of your string. To prevent this a NULL character MUST be added at the end of your string.
A working version is as follows:
char* strcar(char *__s1, const char *__s2)
{
//check inputs for NULL
if(__s1 == NULL || __s2 == NULL)
return NULL;
int s1Length = strlen(__s1);
int s2Length = strlen(__s2);
//ensure strings do not overlap in memory
if(!(__s1 + s1Length < __s2 || __s2 + s2Length < __s1))
return NULL;
//append __s2 to __s1
//the "+ 1" here is necessary to copy the NULL from the end of __s2
for(int i = 0; i < s2Length + 1; i++)
result[s1Length + i] = __s2[i];
}
You Need to add a trailing "\0"-char at the end of __s1.
e.g. insert
__s1[indexOfs1] = 0;
before your return-line.
I was studying about pipes recently and saw this answer:
Connecting n commands with pipes in a shell?
I was intrigued about it and tried to make like a "dynamic" one, in which I introduce a string with n process and then execute the n process (i.e ls | sort). I was trying to tokenize, save in an array, but it did not work. Here is my code of my "tokenizer":
int main()
{
char str[] = "ls | sort";
int length = (sizeof(str) / sizeof(*str))-1;
int sizeCMD = 1; //If the string has zero pipe, it means it has at least 1 process
vector<char> tempV;
for (int i = 0; i < length; i++)
{
if (str[i] == '|')
{//If the string has one |, it means it has at least 2 process.
sizeCMD++;
}
tempV.push_back(str[i]);//I was going to do something else with this, but I forgot.
//cout<<i<<" "<<tempV.at(i)<<endl;
}
int j = 0;//Current position of the cmd
string comLetter = "";//it will save every single letter in certain conditions
string comLine = "";//it will save all the characters of comLetter in certain conditions
struct command cmd[sizeCMD];
const char *ls[2];
const char *sort[2];
const char *toCChar;
for (int i = 0; i < tempV.size(); i++)
{
if (tempV.at(i) != ' ' && tempV.at(i) != '|')
{//comLetter will only save characters that are not equal to blank or |.
//cout<<tempV.at(i);
comLetter += tempV.at(i);
//cout<< comLetter <<endl;
}
if (tempV.at(i) == ' ' || i == tempV.size() - 1)
{//comLine will save everything of comLetter when it detects a blank or the very end
//cout<<comLetter<<endl;
comLine = comLetter;
comLetter = "";
}
if (tempV.at(i) == '|' || i == tempV.size() - 1)
{//cmd will save everything of comLine when it detects a | or the very end.
//cout<<j<<endl;
cout << "." << comLine << "." << endl;
//cout<<i<<endl;
//cout<<toCChar<<endl;
if(comLine == "ls"){
toCChar = comLine.c_str();
ls[0] = toCChar;
ls[1] = 0; //THIS IF
cmd[0] = {ls}; //WORKS
}
if(comLine == "sort"){
sort[0] = "sort";
sort[1] = 0; //THIS IF
cmd[1] = {sort}; //WORKS
}
/*const char *ls[2];
cout<<toCChar<<endl;
ls[0] = toCChar;
ls[1] = 0;
cout<< *ls[0] << " - "<< endl;
cmd[j] = {ls};
//cout << cmd << endl;
comLine = "";*/
j++; //The position will move by one.
}
}
return fork_pipes(sizeCMD, cmd);
}
Everything made sense to me, until I found out that const char* can't be temporal as it needs the data, so I need to create 2 const char* arrays for 2 commands. That's why I've two arrays: *sort[] and *ls[], for sort and ls.
Also, I was wondering, why these lines get "ignored":
toCChar = comLine.c_str();
ls[0] = toCChar;
I'm struggling right now, if someone could please help/guide me on how to do it, I would appreciate that.
I have to copy data into sets of 16 bytes. How do i do it with an easy way?
I've come up with the below algorithm but how do i know if the null terminator has been added? thanks! :)
std::string input
//get message to send to client
std::cout << "Enter message to send (type /q to quit) : ";
getline(std::cin, input);
input += '\n';
const char *data = input.c_str();
len = strlen(data)+1;
int max_len =17;
//split msg into 16 bytes
for(int i = 0; i < len ; i+=max_len)
{
char tempStr[max_len];
//get next 16 bytes of msg and store
for(int j = 0; j < max_len ; j++)
{
tempStr[j] = data[j+i];
}//end of for loop
//Do some stuff to tempStr
}
In your code, the string terminator is not added. You also skip one character between the copies (since you have max_len as 17 while you only copy 16characters).
I would propose a solution using the standard library instead:
std::string::const_iterator pos = input.begin();
while (pos < input.end())
{
// Create a temporary string containing 17 "null" characters
char tmp[17] = {'\0' };
// Make sure we co no copy beyond the end
std::string::const_iterator end =
(pos + 16 < input.end() ? pos + 16 : input.end());
// Do the actual copying
std::copy(pos, end, tmp);
// Advance position
pos += 16;
// Use the string in 'tmp', it is properly terminated
}
const char* data = input.c_str();
int len = input.size(); // don't add 1
for (int i=0; i<len; i+=16)
{
char tempStr[17];
tempStr[16] = 0;
strncpy(tempStr, data + i, 16);
// Do some stuff to tempStr
}
Depending upon what you actually do with tempStr, there might be a solution that involves no copying at all.
for (int i=0; i<len; i+=16)
{
llvm::StringRef sref(data + i, data + std::min(i+16,len));
// use sref
}
llvm::StringRef
Hi there I'm reading a string and breaking each word and sorting it into name email and phone number. with the string joe bloggs joeblog#live.com 12345. But once i break everything down, the individual separated variables which hold the name,email and phone number have garbage characters at the end of them. I cant figure out why.
test file
//test file
#include <iostream>
#include <string>
#include "iofunc.h"
using namespace std;
int main(){
string str1 = "joe bloggs joeblog#live.com 12345";
iofunc func;
cout<<"|-----------------------getname DEMONSTRATION------------------|\n" << endl;
func.getName(str1);
cout<<"the names are: " << func.glob_name << endl;
cout<<"\n|-----------------------getphone DEMONSTRATION------------------|\n" << endl;
func.getPhone(str1);
cout<<"the phone number is:" << func.glob_phone << endl;
cout<<"\n|-----------------------getemail DEMONSTRATION------------------|\n" << endl;
func.getEmail(str1);
cout<<"the email address is:" << func.glob_email << endl;
return 0;
}
here's my get name function, the class is too big to scroll through:)
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
i++;
}
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
}
}
glob_name = string(name_temp);
}
}
}
basic jist of all that is, im using the function called lineProcess to figure out whether there is an email, phone and name in the argument string, And the numberofNames functions gives how many names there are so that I can act accordingly.
I had to use char name_temp to copy just the names from string so that I can extract just that and assign it to the string variable named glob_name. It copies everything i need but it gives me that garbage after each extracted string.
any idea?.
EDITED
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
char name_temp[80];
int index_track = 0;
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
int i = 0;
while(i < arg_len){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
if (special_condition == false){
if (name_count == 1){
int i = 0;
while (arg[i] != ' '){
name_temp[i] = arg[i];
index_track = i;
i++;
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 2 names
if (name_count == 2){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=2){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
//for 3 names
if (name_count == 3){
for (int i = 0; i < arg_len;i++){
if (arg[i] == ' '){
wspace_count++;
}
if (wspace_count !=3){
name_temp[i] = arg[i];
index_track = i;
}
}
name_temp[index_track+1] = '\0';
glob_name = string(name_temp);
}
}
}
When you do things like this:
while(i < arg_len){
name_temp[i] = arg[i];
i++;
}
You are copying the characters of the string to name_tmp, but not the 0 at the end which terminates the string.
add to each new string '\0' end-of string symbol
Garbage characters at the end of a string could indicate that you're not null-terminating the string (ending it with a 0x00 byte). This causes the string to continue reading until the next null character, which is actually past where the string's memory ends. This could even cause a segmentation fault in some cases.
You can fix this by adding '\0' to the end of each new string you create. Note that you will have to allocate a string one byte larger now, to hold that new ending character.
The others have pointed you in the right direction, you aren't appropriately terminating your c strings. Declaring a char array of length 80 just points to a block of memory, it doesn't initialise the array in any way, this means that unless you /0 terminate the string you copy into it, you'll get all the crap lying around on the end up to the 80 characters.
I've not written C++ in probably 15 years so the code below may not even work but hopefully it'll give you some ideas for a more elegant and maintainable solution.
void iofunc::getName(string arg){
lineProcess(arg);
//make sure to call this depending on what function u are using
int name_count = 0;
int wspace_count = 0;
int arg_len = arg.length();
//int char_len = 0;
string name_temp;
// Let's assemble a c-str version if the inbound arg string
char* cstr;
cstr = new char [arg.size()+1];
strcpy (cstr, arg.c_str());
name_count = numberofNames();
//line process was called before so this will work,
//make sure you call line process before using this function
//for special, condition when there is no space in front of names
if (special_condition == true){
glob_name = arg;
}
if (special_condition == false){
// Assuming there's at least 1 name, which we have to otherwise the original
// code may never set glob_name, let's use the C String function strtok
// to tokenise our newly created c string at each " ".
// Grab the first name.
name_temp = string(strtok(cstr, " "));
for (int i = 1; i < name_count; i++) {
// Grab names 2 to name_count as required and append them to name_temp
// We need to reinsert the space as strtok doesn't grab it.
name_temp += " " + string(strtok(NULL, " "));
}
// Assign our final name to glob_name
glob_name = name_temp;
}
}
I created a program in C++ that remove commas (,) from a given integer. i.e. 2,00,00 would return 20000. I am not using any new space. Here is the program I created:
void removeCommas(string& str1, int len)
{
int j = 0;
for (int i = 0; i < len; i++)
{
if (str1[i] == ',')
{
continue;
}
else
{
str1[j] = str1[i];
j++;
}
}
str1[j] = '\0';
}
void main()
{
string str1;
getline(cin, str1);
int i = str1.length();
removeCommas(str1, i);
cout << "the new string " << str1 << endl;
}
Here is the result I get:
Input : 2,000,00
String length =8
Output = 200000 0
Length = 8
My question is that why does it show the length has 8 in output and shows the rest of string when I did put a null character. It should show output as 200000 and length has 6.
Let the standard library do the work for you:
#include <algorithm>
str1.erase(std::remove(str1.begin(), str1.end(), ','), str1.end());
If you don't want to modify the original string, that's easy too:
std::string str2(str1.size(), '0');
str2.erase(std::remove_copy(str1.begin(), str1.end(), str2.begin(), ','), str2.end());
You need to do a resize instead at the end.
Contrary to popular belief an std::string CAN contain binary data including 0s. An std::string 's .size() is not related to the string containing a NULL termination.
std::string s("\0\0", 2);
assert(s.size() == 2);
The answer is probably that std::strings aren't NUL-terminated. Instead of setting the end+1'th character to '\0', you should use str.resize(new_length);.
Edit: Also consider that, if your source string has no commas in it, then your '\0' will be written one past the end of the string (which will probably just happen to work, but is incorrect).
The std::srting does not terminate with \0, you are mixing this with char* in C. So you should use resize.
The solution has already been posted by Fred L.
In a "procedural fashion" (without "algorithm")
your program would look like:
void removeStuff(string& str, char character)
{
size_t pos;
while( (pos=str.find(character)) != string::npos )
str.erase(pos, 1);
}
void main()
{
string str1;
getline(cin, str1);
removeStuff(str1, ',');
cout<<"the new string "<<str1<<endl;
}
then.
Regards
rbo
EDIT / Addendum:
In order to adress some efficiency concerns of readers,
I tried to come up with the fastest solution possible.
Of course, this should kick in on string sizes over
about 10^5 characters with some characters to-be-removed
included:
void fastRemoveStuff(string& str, char character)
{
size_t len = str.length();
char *t, *buffer = new char[len];
const char *p, *q;
t = buffer, p = q = str.data();
while( p=(const char*)memchr(q, character, len-(p-q)) ) {
memcpy(t, q, p-q);
t += p-q, q = p+1;
}
if( q-str.data() != len ) {
size_t tail = len - (q-str.data());
memcpy(t, q, tail);
t += tail;
}
str.assign(buffer, t-buffer);
delete [] buffer;
}
void main()
{
string str1 = "56,4,44,55,5,55"; // should be large, 10^6 is good
// getline(cin, str1);
cout<<"the old string " << str1 << endl;
fastRemoveStuff(str1, ',');
cout<<"the new string " << str1 << endl;
}
My own procedural version:
#include <string>
#include <cassert>
using namespace std;
string Remove( const string & s, char c ) {
string r;
r.reserve( s.size() );
for ( unsigned int i = 0; i < s.size(); i++ ) {
if ( s[i] != c ) {
r += s[i];
}
}
return r;
}
int main() {
assert( Remove( "Foo,Bar,Zod", ',' ) == "FooBarZod" );
}
Here is the program:
void main()
{
int i ;
char n[20] ;
clrscr() ;
printf("Enter a number. ") ;
gets(n) ;
printf("Number without comma is:") ;
for(i=0 ; n[i]!='\0' ; i++)
if(n[i] != ',')
putchar(n[i]) ;
getch();
}
For detailed description you can refer this blog: http://tutorialsschool.com/c-programming/c-programs/remove-comma-from-string.php
The same has been discussed in this post: How to remove commas from a string in C
Well, if youre planing to read from a file using c++. I found a method, while I dont think thats the best method though, but after I came to these forums to search for help before, I think its time to contribute with my effort aswell.
Look, here is the catch, what I'm going to present you is part of the source code of the map editor Im building on right now, that map editor obviously has the purpose to create maps for a 2D RPG game, the same style as the classic Pokemon games for example. But this code was more towards the development of the world map editor.
`int strStartPos = 0;
int strSize = 0;
int arrayPointInfoDepth = 0;
for (int x = 0; x < (m_wMapWidth / (TileSize / 2)); x++) {
for (int y = 0; y < (m_wMapHeight / (TileSize / 2)); y++) {
if (ss >> str) {
for (int strIterator = 0; strIterator < str.length(); strIterator++) {
if (str[strIterator] == ',') {`
Here we need to define the size of the string we want to extract after the previous comma and before the next comma
`strSize = strIterator - strStartPos;`
And here, we do the actual transformation, we give to the vector that is a 3D vector btw the string we want to extract at that moment
`m_wMapPointInfo[x][y][arrayPointInfoDepth] = str.substr(strStartPos, strSize);`
And here, we just define that starting position for the next small piece of the string we want to extract, so the +1 means that after the comma we just passed
strStartPos = strIterator + 1;
Here, well since my vector has only 6 postions that is defined by WorldMapPointInfos we need to increment the third dimension of the array and finally do a check point where if the info has arrived the number 6 then break the loop
arrayPointInfoDepth++;
if (arrayPointInfoDepth == WorldMapPointInfos) {
strStartPos = 0;
arrayPointInfoDepth = 0;
break;
}
}
}
}
}
}
Either way on my code, think abt that the vector is just a string, thats all you need to know, hope this helps though :/
Full view:
int strStartPos = 0;
int strSize = 0;
int arrayPointInfoDepth = 0;
for (int x = 0; x < (m_wMapWidth / (TileSize / 2)); x++) {
for (int y = 0; y < (m_wMapHeight / (TileSize / 2)); y++) {
if (ss >> str) {
for (int strIterator = 0; strIterator < str.length(); strIterator++) {
if (str[strIterator] == ',') {
strSize = strIterator - strStartPos;
m_wMapPointInfo[x][y][arrayPointInfoDepth] = str.substr(strStartPos, strSize);
strStartPos = strIterator + 1;
arrayPointInfoDepth++;
if (arrayPointInfoDepth == WorldMapPointInfos) {
strStartPos = 0;
arrayPointInfoDepth = 0;
break;
}
}
}
}
}
}