strange case of assigning string to a variable in c++ - c++

1. vector<string> cmdv=explode(" ","i am a string");
2. std::string arg;
3. char * args[10];
4. for (i = 0; i < cmdv.size(); i++) {
5. arg = std::string(cmdv[i]);
6. if (cmdv[i][0] == '"') {
7. //do some thing
8. }
9. args[i] = arg.c_str();;
10. }
11. args[i]='\0';
I expected the contents of args array {"i","am","a","string"} but args array is {"am","a","string","string"}
on debug i found that at line 6 in if clause when cmdv[i][0] is compared with '"', args[i-1] is being replaced with contents of arg. I got baffled!
there is no problem with explode function. Its working good.

This is a problem :-
args[i] = arg.c_str();
The pointer returned by this is only valid while arg contains it's value and you alter arg each time through your loop. If you want to store a C style pointer to the string you'll need to make a copy of it, maybe something like :-
args[i] = strdup(arg.c_str());
But remember to free it. Plus there is probably a better way to achive what you want than using C style strings anyway

Related

Join an array of strings

The question is simple. I'm looking for an easy and efficient way of joining an array of strings (or arrays of any other type, for that matter, since strings are an alias for char[]), with an optional separator.
In JavaScript, this functionality would already exist with the join method. Being new to D, I failed to find something as easy as that in the standard library. It would be too bad if I had to implement a utility function myself.
So instead of something like this:
string merge (const string arr[] , const string separator) {
if (arr.length == 0) return "";
string r = arr[0];
for (int i = 1 ; i < arr.length ; i++) {
r ~= separator ~ arr[i];
}
return r;
}
What would an experienced D programmer do?
I'm not a D programmer, but I'll take a crack at it, the library reference has a join method.
From the docs:
const string[] arr = ["apple", "banana"];
assert(arr.join(",") == "apple,banana");
assert(arr.join() == "applebanana");
See also std.algorithm.joiner for a version that is lazy and doesn't allocate any memory.

c++ dynamic allocation initial values

I'm trying to concatenate two strings into a new one (finalString) like this:
finalString = string1 + '&' + string2
Firstly, I allocate the memory for finalString, then i use strcat().
finalString = new char[strlen(string1 ) + strlen(string2) + 2];
cout << finalString << endl;
finalString = strcat(finalString , string1 );
finalString = strcat(finalString , "&");
finalString = strcat(finalString , string2);
cout << finalString << endl;
I'll suppose that string1 is "Mixt" and string2 is "Supermarket".
The output looks like this:
═════════════════řřřř //(which has 21 characters)
═════════════════řřřřMixt&Supermarket
I know that if I use round brackets in "new char" the string will be initialized to 0 and I'll get the desired result, but my question is why does the first output has 21 characters, supposing that I allocated only 17. And even so, why does the final string length exceed the initial allocation size (21 > 17) ?
Thanks in advance!
Two words for you "buffer overrun"
The reason you have 21 characters initially is because there is a '/0' (also called null) character 22 characters away from the memory address that finalString points to. This may or may not be consistent based on what is in your memory.
As for the reason why you have a longer than what you wanted again you wrote outside the initial buffer into random memory. You did not crash because you did not write over something important.
strcat will take the memory address given, find the first '/0' it finds and from that place on it will copy the data from the second memory pointer you provide until the first '/0' it finds there.
What you are doing is VERY DANGEROUS, if you do not hit a /0' before you hit something vital you will cause a crash or at minimum bad behavior.
Undersand in C/C++ a char[] is just a pointer to the initial memory location of the first element. THERE ARE NO SAFEGUARDS! You alone must be careful with that..
if you set the first character of the finalString[0] = 0 then you the logic will work better.
As a different answer, why not use std::string:
std::string a, b, c;
a = "part1";
b = "part2";
c = a + " & " + b;
std::cout << c << '\n';
part1 & part2
Live example: http://ideone.com/pjqz9T
It will make your life easier! You should always look to use stl types with c++.
If you really do need a char * then at the end you can do c.c_str().
Your string is not initialized which leads to undefined behavior. In strcat, string will be appended when it finds the null character.
So, as others already mentioned, either you can do
finalString[0] = 0;
or in place of your first strcat use strcpy. This will copy the first string and put a null character at the end.
why 21 characters?
This is due to undefined behavior. It will keep on printing until it won't find a null or else it will crash as soon as it tries to access any illegal memory.

What exactly happens if I assign a value to a string position that is not used at the moment?

I almost never use the c++ string type but I'll need to use a set of strings so I think they would be the best way to go...
I coded like this:
string a;
a[0] = 'b';
printf("%s", a.c_str());
and it printed the letter 'b'
but when I tried:
string a;
// i bellow would be a number from 0 to 9, so I add 48 to get the correspondent char
a[0] = 48 + i;
printf("%s", a.c_str());
It is not printing a single digit...
My question is: did it print 'b' correctly in the first case just because of a lucky undefined behavior?
I'm asking that because if I already had something in position 0, the assignment a[0] = 48 + i; would print the number correctly.
String is a dynamic array so you cant call to undefined part of memory. The calling
string a;
a[0] = 'b';
printf("%s", a.c_str());
Is very dangerous because u already access to other part of memory and overwrote this. I guess your program will throw an error in other part of program. Look what u did:
string a; a[0] = 'b'; printf("%d ", a.size()); output will be of course 0.
You have to reserve memory before that like: a.resize(10)
Please correct me anyone, if this is a platform dependent answer. I used VS2012 and had no time to test with gcc.
Once you creates a string like,
string s;
It allocates some initial memory. You can see it by,
s.capacity();//For me it gets 15
It returns some non-zero value (again in VS2012). So, having,
s[0] = 'b';
is meaningful.
If you try something,
a[10000] = 'b';
It'll crash your program.
The case for a[0] = 48 + i ( 0 <= i <= 9), I'd say this shouldn't be a problem other than it prints some gibberish after your single digit.

c++ string member function substr usage

Please tell me if I am understanding the the substr member function correctly?
result = result.substr(0, pos) + result.substr(pos + 1);
It takes the string from pos, 0 until (but not including), remove[i]
and then + result.substr(pos + 1); concatenates the rest of the string, except but not including the string / char in remove?
string removeLetters2(string text, string remove)
{
int pos;
string result = text;
for (int i = 0; i < remove.length(); i++)
{
while (true)
{
pos = result.find(remove[i]);
if (pos == string::npos)
{
break;
}
else
{
result = result.substr(0, pos) +
result.substr(pos + 1);
}
}
}
return result;
}
In short, you are asking if
result = result.substr(0, pos) +
result.substr(pos + 1);
removes the character at position pos, right?
Short Answer:
Yes.
Longer Answer:
The two-argument call takes the start index and the length (the one argument call goes to the end of string).
It helps to imagine the string like this:
F o o / B a r
0 1 2 3 4 5 6 <- indices
Now remove /:
F o o / B a r
0 1 2 3 4 5 6 <- indices
1 2 3 | <- 1st length
| 1 2 3 <- 2nd length
result = result.substr(0, 3) <- from index 0 with length 3
+ result.substr(4); <- from index 4 to end
As a programmer, always be aware of the difference between distance/index and length.
Better: If index is known:
Your code creates two new, temporary strings, which are then concatenated into a third temporary string, which is then copied to result.
It would be better to ask string to erase (wink wink) in place:
result.erase(pos,1);
// or by iterator
string::iterator it = ....;
result.erase(it,it+1);
This leaves more optimization freedom to the string implementer, who may choose to just move all characters after pos by one to the left. This could, in a specialized scenario, be implemented with a single assignment, a single loop, and within the loop with the x86 swap instruction.
Better: If characters to be deleted are known:
Or, but I am not sure if this gives better performance, but it may give better code, the algorithm remove_if:
#include <algorithm>
// this would remove all slashes, question marks and dots
....
std::string foobar = "ab/d?...";
std::remove_if (foobar.begin(), foobar.end(), [](char c) {
return c=='/' || c=='?' || '.';
});
remove_if accepts any function object.
If there is just one character, it gets easier:
// this would remove all slashes
std::remove (foobar.begin(), foobar.end(), '/');
Although the answer to your question is "yes", there is a better way to go about what you are trying to do. Use string::erase, like this:
result.erase(pos, 1);
This API is designed for removal of characters from the string; it achieves the same result much more efficiently.
Yes, this function removes all letters in remove from text.
since you seem to delete more than one type of character have a look at remove_if from <algorithm> with a special predicate too, although the response of dasblinkenlignt is the good one

Incrementing pointers in C++

Why are the two following code segments not equivalent?
void print (char* s) {
if (*s == '\0')
return;
print(s+1);
cout << *s;
}
void print (char* s) {
if (*s == '\0')
return;
print(++s);
cout << *s;
}
The ++ operator increments the pointer value, but then returns the original value ... so print(s++) will print the value of s before the increment, since even though it adds a value of 1 to s, making the value stored at s equal to s+1, it still returns the original value of s as the result of the operation. On the otherhand print(s+1) prints the value after the increment, but very importantly does not modify the original value of s. So the result of the statement s+1 is just a new temporary pointer value ... the original value of s is not modified.
Furthermore, since you've incremented and changed the value of s with the ++ operator, when you call cout, you're now printing the value to wherever the new pointer is pointing (this could cause a crash or segmentation fault if you're not careful and there's no user accessible memory at the new memory location s is pointing to). With s+1, the value of s remains unmodified, so the result of cout will be to wherever s was originally pointing.
Edit:
As Michael points out, this is actually a recursive function, so the second example simply keeps calling print() with the same argument, since as mentioned before, the returned value from s++ is the original value of s. That means you'll end up with a stack overflow at some point and just crash unless the value that s pointed to was already the NULL character.
Since it looks like the OP changed print(s++) to print(++s), which is hugely different, here's an explanation for this new version.
In the first example, you have:
print(s+1);
cout << *s;
s+1 does not modify s. So if s is 4, and you print(s+1), afterwards s will still be 4.
print(++s);
cout << *s;
In this case, ++s modifies the local value of s. It increments it by 1. So if it was 4 before print(++s), it will be 5 afterwards.
In both cases, a value equivalent to s+1 would be passed to the print function, causing it to print the next character.
So the difference between the 2 functions is that the first one will recursively print character #0, then 1, 2, 3, ..., while the second function prints 1, 2, 3, 4, ... (it skips the first character and prints the "\0" afterwards).
Example:
For the s+1 version, print("hello") will result in h e l l o
For the ++s version, print("hello") will result in e l l o \0
Both of the expressions s++ and s+1 are to do with increasing the position of the pointer itself, not the value contained at the pointer locations
The value of s++ is just s, and the value of s+1 is, well, one position further on than s!
The value of s after executing s++ is one position further on than it was before. After using s+1, the value of s is unchanged.
Therefore the order they print out the letters is reversed!
I will try to explain an example of pre and post increment from which you can solve the question posted yourself.
#include <iostream>
void foo(int num)
{
std::cout << num << "\n" ;
}
int main()
{
int number = 10 ;
foo( number++ ) ;
foo( ++number ) ;
foo( number + 1 ) ;
getchar() ;
return 0 ;
}
Output:
10
12
13
Why 10?
foo( number++ ) ;
Post-increment operation is done on number. Meaning, value of number is first passed to foo and then the value of number is incremented upon foo return. So, after function return, number is 11.
Why 12?
foo( ++number ) ;
Pre-increment operation is done on number. Meaning, before even call to foo, the value of number is incremented to 12. And then it is passed to foo. So, even after the function return, number is still 12.
Why 13?
It's just straight forward. Value of number is not modified but passed a value adding 1 to the value of number. In this process, number is not modified. So, even after function return, number is still 12.
Hope this helps to solve the problem yourself ( though in your case it is paper-pencil exercise ) :)