strcat Function in c++ - c++

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.

Related

Trimming start of Cstring without copying

I managed to get my homework to work but It shouldn't work because i have not finished it. I don't know why it does. I need help.
#include<iostream>
using namespace std;
char* trim(char* str) {
const int lenStr = strlen(str);
int characters = 0;
bool trimmableFront = false;
int firstChar;
//check if trimmableFront + location of first char
for (int i = 0; i < lenStr; i++) {
if (*(str + i) != ' ') {
if (characters == 0)
firstChar = i;
characters++;
}
if (characters == 0) {
trimmableFront = true;
}
}
//trim Front //THIS PART SHOULD BEHAVE DIFFERENTLY
if (trimmableFront) {
for (int i = 0; i < lenStr; i++) {
if((firstChar + i <= lenStr))
*(str + i) = *(str + firstChar + i);
}
}
return str;
}
int main() {
char str[] = " why does it work?";
trim(str);
cout<< str <<endl;
return 0;
}
At the end of trim(*char) function, trimmed string should have still leftovers from previous locations.
For some reason it is perfectly trimmed and works as intended printing "why does it work?" but it should print something like "why does it workt work?"
The reason why it works is because as you trim the string by shifting each character you also shift the terminating null character '\0'. As you probably know c-strings are array of characters terminated by '\0', so as you print str with cout all characters are printed until the null value is reached: that is way the leftovers are not printed.

C++ Letters -> Numbers

This is my first time posting a question to Stack Overflow. I am new at programming so please excuse me if I say things strange or wrong. In the file below; it reads the directory and saves it to a variable nAddress. It then removes the file extension; breaks up the file into 700 lines each rebuilds the extension; and lastly, increments the filename by 1 letter IE: testA, testB, testC, testD, etc.
Reworded:
Current Output:
Test is 1400 lines so it outputs
TestA
TestB
IT NEEDS TO BE:
Test1
Test2
Could you point me in the right direction? Thanks!
string fAddress = argv[1];
if (argc > 2)
{
for (int i = 2; i < argc; i++)
{
string temp = argv[i];
fAddress = fAddress + " " + temp;
}
}
cout << fAddress << "\n" <<endl;
// Convert to a char*
const size_t newsize = 500;
char nstring[newsize];
strcpy_s(nstring, fAddress.c_str());
strcat_s(nstring, "");
// Convert to a wchar_t*
size_t origsize = strlen(fAddress.c_str()) + 1;
size_t convertedChars = 0;
wchar_t wcstring[newsize];
mbstowcs_s(&convertedChars, wcstring, origsize, fAddress.c_str(), _TRUNCATE);
wcscat_s(wcstring, L"");
ifstream inFile;
inFile.open (wcstring);
int index = 0;
string parts[100];
string text;
for (int i = 0; i < 100; i++)
{
parts[i] = "";
}
// get info until ; is found in each line and add it to the array of char*
while ( !inFile.eof( ) )
{
getline(inFile, text, (char)1);
if ( !inFile )
{
if (inFile.eof( ) )
break;
else
{
cout << "File error...\n";
break;
system("PAUSE");
}
}
parts[index] += text;
index++;
}
inFile.close();
int n = fAddress.length(); // Get the total size of the file name.
string nAddress = "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++";
cout<<"Removing previous file extension...\n";
n = n - 4; //Remove the extension from the output file
cout<<"Removed previous file extension successfully...\n\n";
cout<< "Building file location and name....\n";
for (int i = 0; i < n; i++)
{
nAddress[i] = nstring[i]; //nstring hold the name
}
cout<< "Built successfully....\n\n";
//Now nAddress is equal to the location and name of the file....
nAddress[n] = '0' ;//'A';
cout<<nAddress[n];
// nAddress[n+1] = 1+48;
//system("cls");
cout<< "Building file extension...\n"<< endl;
for (int i = n; i < n+4; i++) // n is whatever the length of the string is. Add 4 chars onto the n.
{
nAddress[i+1] = nstring[i];
fileextension = fileextension + nstring[i]; //This saves off the full file extension for later use. :)
//cout <<nAddress; This seems to build the extension of the file... IE .T, .TA, .TAP
}
cout<< "File extension built successfully...\n"<< endl;
nAddress[n+5] = '\0';
//cout<< nAddress;
string files[10];
//This is the part that searches through the file and splits it up I believe.
for (int i = 0; i < index-2; i++)
{
files[i] = parts[0] + parts[i+1] + parts[index-1];
//cout<< files[i]; //This line will output the entire file in the CMD window
}
//system("cls");
// The function below is where the names are dished out
nAddress[n-20];
int counter = 0;
int lastnum;
for (int i = 0; i < index-2; i++)
{
//string myval;
//ostringstream convert;
//counter++;
//convert << counter ;
nAddress[n] = i + 65; //this is the line that gives the letters... it comes in with an A as the first file FYI
//nAddress = nAddress + convert.str();
//cout<<convert.str();
//cout<<counter;
//myval = nAddress[n];
//cout<<myval;
cout<<"Outputting sub-files...\n" <<endl;
cout<<nAddress<< "\n" << endl;
size_t origsize = strlen(nAddress.c_str()) + 1;
size_t convertedChars = 0;
wchar_t wcstrings[newsize];
mbstowcs_s(&convertedChars, wcstrings, origsize, nAddress.c_str(), _TRUNCATE);
wcscat_s(wcstrings, L"");
ofstream outFile (wcstrings);
outFile << files[i];
}
Use s.th. like this:
std::string getPartFilename(int partNumber)
{
std::ostringstream oss;
oss << "Test" << partNumber;
return oss.str();
}
UPDATE
To clarify my point: Refactor your code to remove all those pesky c string operations (strcpy_s() , strcat_s(), etc.) for building the file names, and use a simple straightforward C++ standard mechanism to format the strings as you need them.
okay, so if
nAddress[n] = i + 65;
is truly where the incremented letter of the file gets set, than here's what I'd do.
since you're using std:string,
// make your address just "test"
nAddress[n] = '\0';
// cast `i` to a string and concatinate
nAddress += to_string(i);
http://www.cplusplus.com/reference/string/to_string/
http://www.cplusplus.com/reference/string/string/operator+=/
If you weren't using std:string you'd approach it like this
// make your address just "test"
nAddress[n] = '\0';
// make a character array that contains the character representation of `i`
char buffer[50];
sprintf("%d", i);
// concatinate
strcat(nAddress, buffer);
or, you can merely do
sprintf(&nAddress[n], "%d", i);
as indiv mentioned
To change the letter to a number (if I understand the code correct),
nAddress[n] = i + 65;
should become
nAddress[n] = i + '0';

Converting a const string into an array of ints?

Hello I am trying to convert a const character string into an array of ints but when I try it does not allow it. My code is:
int isRegistered(const char str[]) {
int isbnInt[10], i;
//char isbnArray[10];
//isbnArray = str; ----> something I tried
for (i = 0; i < 10; i++)
{
isbnInt[i] = atoi(str[i]);
cout << isbnInt[i] << endl;
}
}
But when I try to compile it, I get an error saying "invalid conversion from char to const char*"
atoi call expects a const char * arguement, while you pass a char, this is the problem.
You can just do the below to convert the character to number. This subtracts the ascii value of 0 from the character itself ( since 0-9 are sequentially increasing in the ascii code.)
isbnInt[i] = str[i] - '0';
Try:
for (i = 0; i < 10; i++)
{
isbnInt[i] = str[i] - '0';
cout << isbnInt[i] << endl;
}
atoi takes const char* as input instead of single char.
Your code could also be written:
for (i = 0; i < 10; i++)
{
char foo = str[i];
isbnInt[i] = atoi(foo);
cout << isbnInt[i] << endl;
}
Which won't work (as you've found); atoi expects a char*, not a char.
Try:
int isbm = atoi(str);
and see if that does what you wanted.

[number]-F appearing at the end of String?

I am a new to c++ and was butchering together a palindrome program at 1am on a Sunday just, because! and I have come across this problem:
Input: test
Reverse: tset3-F
Where has the 3-F come from? Sometimes it's just -F or another number-F. Where is this coming from?
Here is my code:
#include <iostream>
#include <string>
using namespace std;
int main() {
string eString;
int length;
int counter = 0;
cout << "Enter String: ";
cin >> eString;
length = eString.length();
char reverseChar[length];
for(int x = eString.length() -1; x > -1; x--) {
reverseChar[counter] = eString[x];
counter++;
}
cout << "Reverse: " << reverseChar;
}
Many thanks for your time.
You aren't adding a null terminator to the end of your strings. It's random data that happens to be in memory.
reverseChar should be length + 1 in size
The final char should be set to '\0'
reverseChar[length] = '\0';
See: http://en.wikipedia.org/wiki/Null-terminated_string
You need to add a null terminator to the reverseChar string. There is a 0 just after the last character of all strings in C, which tells string manipulation functions where the string ends in memory. The 0 is never included in the length, so you have to remember to add room for it when allocating space for a string.
char reverseChar[length + 1];
for(int x = eString.length() -1; x > -1; x--) {
reverseChar[counter] = eString[x];
counter++;
}
reverseChar[length] = 0;
I think: char reverseChar[length+1] because you need to leave space for the end of string delimiter reverseChar[length]='\0'

remove commas from string

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;
}
}
}
}
}
}