Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 11 months ago.
Improve this question
I have the following code that I'm trying to decipher from a former colleague:
void getIP(int p){
char tstr[80];
char *pt;
strcpy(ipBuf,"NA");
if(p==-1)return;
strcpy(tstr, panes[p].stream.c_str());
pt=strchr(tstr,':');
if(pt){
*pt='x'; //Blank first one
pt=strchr(tstr,':');
if(pt){
*pt='\0';
strcpy(ipBuf,&tstr[7]);
}
}
}
I'm relatively inexperienced with C++ so was hoping I could get some help with how this code works. Its purpose I think is to take a camera stream address and strip the port number and any extra stuff off to just give an IP address. I cannot understand through how it achieves this other than it seems to use ":" as a delimiter at a couple of stages?
To explain the function a little more, int p is a position on the grid, then it takes the stream address from that grid square and puts it into tstr.
But any explanation beyond that is much appreciated.
I [...] was hoping I could get some help with how this code works.
strcpy(tstr, panes[p].stream.c_str());
Copy the contents of the std::string designated by panes[p].stream into array tstr, yielding an independent copy as a C string.
pt=strchr(tstr,':');
if(pt){
*pt='x'; //Blank first one
Locate the first appearance of a ':' character in the local copy of the string. If the character is found, then replace it with an 'x'.
pt=strchr(tstr,':');
if(pt){
*pt='\0';
Locate the (new) first appearance of a ':' character in the local copy of the string. If it exists, replace it with a '\0', which will be recognized as a string terminator. That is, truncate the string at that point.
strcpy(ipBuf,&tstr[7]);
Copy the contents of the local C string, starting at the eighth character (because arrays are indexed from 0, not from 1), into the space to which ipBuf points. The magic number 7 is suspicious here, but I don't have enough information to be able to determine whether it is erroneous. My guess would be that the code is assuming that the original first colon will always appear at index 6, with the result that the substring between the (original) first and second colons is copied, but there are cleaner, clearer, more efficient ways to do that.
Improved version, with more C++
... and better names, and no unnecessary copying, and explanatory comments:
void getIP(int pane_index){
if (pane_index >= 0) {
// for clarity and convenience
std::string &url_string = panes[pane_index].stream;
// hardcoded per the original code
const size_t ip_offset = 7;
// Locate the first colon, if any, after the start of the ip address
size_t colon_index = url_string.find(':', ip_offset);
if (colon_index != std::string::npos) {
// Extract the name / IP address as the substring starting at
// offset 7 and stopping just before the second colon
size_t ip_len = colon_index - ip_offset;
strncpy(ipBuf, url_string.c_str() + ip_offset, ip_len);
ipBuf[ip_len] = '\0';
return;
} // else there are no colons after the start of the ip address
} // else an invalid pane index was given
// no machine name / IP address is available
strcpy(ipBuf, "NA");
}
As already noted in the previous comment, the function searches for the second occurence of ':' in tstr string and if it is found, replaces it with null character, effectively cutting off any remaining characters from the string. Than the characters in the string from index [7] to the null character (previously ':') are copied to ipBuf. For example, let say url is rtsp://192.168.0.200:551/stream.sdp. Digit 1 in "192" has index [7] in the string. So copying from that position to the second ":" (or null char) would copy "192.168.0.200".
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
This post was edited and submitted for review 3 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Improve this question
I'm having problems with this simple example.
The program inquires as to how many letters are required to form a complete word. Then it will ask for each letter individually, which is fine, but I can't make the code save the value from the current character and the next one from the next iteration until the number of letters finishes the word and print it to confirm the word.
E.g. Let's say house, which has 5 letters.
int numbersOfCharacters=5;
int counter=0;
char character;
string phrase;
while (counter < numbersOfCharacters)
{
cout << "Introduce character's number" << counter << ": ";
cin >> character;
counter = counter + 1;
phrase=character+character; //I'm not sure if I need an array here.
}
cout << "Concatenated characters: " << phrase << endl;
The output is:
Introduce the character number 1: h
Introduce the character number 2: o
Introduce the character number 3: u
Introduce the character number 4: s
Introduce the character number 5: e
Concatenated characters: ?
And the expected output should be:
Concatenated characters: house
Update
Using John's comments I was able to resolve the issue. It's not a lack of debugging information but instead know the proper operator for this solution. Thanks also to Remy Lebeau for the detailed info.
The expression phrase=character+character; doesn't do what you think it does. You are taking the user's input, adding its numeric value to itself, and then assigning (not appending) that numeric result as a char to the string.
So, for example, on the 1st iteration, the letter h has an ASCII value of 104, which you double to 208, which is outside the ASCII range. On the next iteration, the letter o is ASCII 111 which you double to 222, which is also outside of ASCII. And so on. That is why the final string is not house like you are expecting.
Perhaps you meant to use phrase=phrase+character; instead? But, that won't work either, because you can't concatenate a char value directly to a string object using operator+.
What you can do is use string::operator+= instead:
phrase += character;
Or the string::push_back() method:
phrase.push_back(character);
I'm stuck on an assignment which converts contents of an array (input from the user) to a pre-declared shorthand.
I want it to be as simple as strcpy(" and ", "+");
to change the word 'and' within a string, to a '+' sign.
Unfortunately, no matter how I structure the function; I get a deprecated conversion warning (variant loops, and direct applications, attempted).
Side note; this is assignment based, so my string shortcuts are severely limited, and no pointers (I've seen several versions of clearing the fault using them).
I'm not looking for someone to do my homework; just guidance on how strcpy can be applied without creating the dep. warning. Perhaps I shouldn't be using strcpy at all?
strcpy copies the contents of the second string into the memory of the first string. Since you're copying a string literal into a string literal it can't do it (you can't write to a string literal) and so it complains.
Instead you need to build your own search and replace system. You can use strstr() to search for a substring within a string, and it returns the pointer in memory to the start of that found string (if it's found).
Let's take the sample string Jack and Jill went up the hill.
char *andloc = strstr(buffer, " and ");
That would return the address of the start of the string (say 0x100) plus the offset of the word " and " (including spaces) within it (0x100 + 4) which would be 0x104.
Then, if found, you can replace it with the & symbol. However you can't use strcpy for that as it'll terminate the string. Instead you can set the bytes manually, or use memcpy:
if (andloc != NULL) { // it's been found
andloc[1] = '&';
andloc[2] = ' ';
}
or:
if (andloc != NULL) { // it's been found
memcpy(andloc, " & ", 3);
}
That would result in Jack & d Jill went up the hill. We're not quite there yet. Next you have to shuffle everything down to cover the "d " from the old " and ". For that you'd think you could now use strcpy or memcpy, however that's not possible - the strings (source and destination) overlap, and the manual pages for both specifically state that the strings must not overlap and to use memmove instead.
So you can move the contents of the string after the "d " to after the "& " instead:
memmove(andloc + 3, andloc + 5, strlen(andloc + 5) + 1);
Adding a number to a string like that adds to the address of the pointer. So we're looking at copying the data from 5 characters further on in the string that the old "and" location into a space starting at 3 characters on from the start of the old "and" location. The amount to copy is the length of the string from 5 characters on from the start of the "and" location plus one so it copies the NULL character at the end of the string.
Another manual way of doing it would be to iterate through each character until you find the end of the string:
char *to = andloc + 3;
char *from = andloc + 5;
while (*from) { // Until the end of the string
*to = *from; // Copy one character
to++; // Move to the ...
from++; // ... next character pair
}
*to = 0; // Add the end of string marker.
So now either way the string memory contains:
Jack & Jill went up the hill\0l\0
The \0 is the end of string marker, so the actual string "content" is only up as far as the first \0 and the l\0 is now ignored.
Note that this only works if you are replacing a part with something that is smaller. If you are replacing it with something bigger, so the string grows in size, you will be forced to use memmove, which first copies the content to a scratchpad, and ensure that your buffer has enough room in it to store the finished string (this kind of thing is often a big source of "buffer overruns" which are a security headache and one of the biggest causes of systems being hacked). Also you have to do the whole thing backwards - move the latter part of the string first to make room, then modify the gap between the two halves.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
Given a character array in a URL format like
char *s="www.google.com\tsp finite.aspx"
While decoding it space should be replaced by %20 and thus the string becomes:
char *s="www.google.com\tsp%20finite.aspx"
We are not allowed to use a new character array but allowed to use some character variables for temporary use. Should not use any containers also. The array contains enough space to contain the decoded data so no need to worry about the more space to be taken.
I followed the Brute-Force mechanism where all the characters from the point of finding a space to the end of the array are to be swapped. But this is not the most efficient way to solve the problem.
Can any body tell me which is the best way (algorithm) to decrease the no. of swappings in order to acquire the solution.
I am assuming the string has been allocated using malloc
First calculate the number of spaces and the length of the string
Then the new length = old length + number of spaces * 2. Use realloc to expand the string.
The work backwards from the end and copy to the new length. When encountering space copy in %20 instead.
The main problem could be that swapping space with %20 will require moving the whole string 2 characters more .
Here's an idea :
Parse the whole string once, and count the number of spaces in the string
The new length of the array would be strlen(original) + 2*(nOfSpaces) (let's call it from now on NewLen)
Parse the whole string once again but starting backwards.
You will copy the previous string contents inside itself but at an offset until you hit a space
you will have a pointer starting at strlen(original) and one starting at NewLen
parse from strlen(original) backwards until you find a space (the substrLen will be subLen)
memcpy from [strlen(original)-curParsingindex] to [NewLen - curParsingIndex-2*(enteredSpaces)] sublen amount
Instead of copying the space, put %20 instead
This way you will avoid moving the string forward each time you hit a space.
Regarding step 4 , you might think about using a temporary variable for the sublen, since you might end up writing in the same memory zone by mistake (take an example where all the spaces are at the beginning).
This is a classic interview coding question; a good solution for this starts with a good interface for your solution. Something that works is:
char* replaceChar(char* in, char c)
char *in - string you want to decode
c - the char you want to replace with it's hexa value ASCII code ( HEX val ascii for ' ' is 0x20)
Pseudocode:
allocate a buffer the same size as the input buffer
get the index of the first occurrence of the char you want to replace (strcspn can help with that)
copy the content of the of the input up to the found index to the new buffer.
reallocate the new buffer size to newSize=oldSize+2
add % to the new string
repeat until you reach the end of the string.
return a pointer to the new string
You can also do it in place on the original string but that solution is a bit more complicated because you have to shift everything.
You can do it in two passes. The key idea is to first count the number of spaces and then move each character directly to its final position. In your approach you shift the remainder of the string at each occurrence of a space.
#include <stdio.h>
int main ()
{
char str[1000] = "www.example.com/hello world !";
int length;
int spaces;
int i;
char *ptr;
printf ("\"%s\"\n", str);
// pass 1:
// calculate length and count spaces
length = 0;
spaces = 0;
for (ptr = str; *ptr; ptr++) {
if (*ptr == ' ') {
spaces++;
}
length++;
}
// pass 2:
// transform string
// preserve terminating null character
ptr = str + length + 2 * spaces;
for (i = length; i >= 0; i--) {
char c = str[i];
if (c == ' ') {
*ptr-- = '0';
*ptr-- = '2';
*ptr-- = '%';
}
else {
*ptr-- = c;
}
}
printf ("\"%s\"\n", str);
return 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
How to find the first occurrence of a character from the end, but at the same time indicate the position of the end of the string at which to look for?
Ie we need the following function.
lastIndexOf(char c, int position_from_end);
As will be:
QString s("abcadc");
int i = s.mylastIndexOf('c', 0) //6
.
QString s1("abcadc");
int j = s1.mylastIndexOf('c', 1) //3
In c++, use the std::string method rfind(char c, size_t pos)
The character will be searched for in the part of the string which comes before index pos. (If you were to use the version of rfind which searches for a substring, the first character of the match must come before pos).
pos defaults to string::npos, which is larger than any valid string index and therefore causes the search to start at the end of the string.
It returns string::npos if no match is found.
If you want to specify the offset from the end of the string, you can subtract the offset from the string's length:
std::string s;
//...
size_t p = s.rfind(ch, s.size() - offset);
I'm writing a program that will balance Chemistry Equations; I thought it'd be a good challenge and help reinforce the information I've recently learned.
My program is set up to use getline(cin, std::string) to receive the equation. From there it separates the equation into two halves: a left side and right side by making a substring when it encounters a =.
I'm having issues which only concerns the left side of my string, which is called std::string leftSide. My program then goes into a for loop that iterates over the length of leftSide. The first condition checks to see if the character is uppercase, because chemical formulas are written with the element symbols and a symbol consists of either one upper case letter, or an upper case and one lower case letter. After it checks to see if the current character is uppercase, it checks to see if the next character is lower case; if it's lower case then I create a temporary string, combine leftSide[index] with leftSide[index+1] in the temp string then push the string to my vector.
My problem lies on the first iteration; I've been using CuFe3 = 8 (right side doesn't matter right now) to test it out. The only thing stored in std::string temp is C. I'm not sure why this happening; also, I'm still getting numbers in my final answer and I don't understand why. Some help fixing these two issues, along with an explanation, would be greatly appreciated.
[CODE]
int index = 0;
for (it = leftSide.begin(); it!=leftSide.end(); ++it, index++)
{
bool UPPER_LETTER = isupper(leftSide[index]);
bool NEXT_LOWER_LETTER = islower(leftSide[index+1]);
if (UPPER_LETTER)// if the character is an uppercase letter
{
if (NEXT_LOWER_LETTER)
{
string temp = leftSide.substr(index, (index+1));//add THIS capital and next lowercase
elementSymbol.push_back(temp); // add temp to vector
temp.clear(); //used to try and fix problem initially
}
else if (UPPER_LETTER && !NEXT_LOWER_LETTER) //used to try and prevent number from getting in
{
string temp = leftSide.substr(index, index);
elementSymbol.push_back(temp);
}
}
else if (isdigit(leftSide[index])) // if it's a number
num++;
}
[EDIT] When I entered in only ASDF, *** ***S ***DF ***F was the output.
string temp = leftSide.substr(index, (index+1));
substr takes the first index and then a length, rather than first and last indices. You want substr(index, 2). Since in your example index is 0 you're doing: substr(index, 1) which creates a string of length 1, which is "C".
string temp = leftSide.substr(index, index);
Since index is 0 this is substr(index, 0), which creates a string of length 0, that is, an empty string.
When you're processing parts of the string with a higher index, such as Fe in "CuFe3" the value you pass in as the length parameter is higher and so you're creating strings that are longer. F is at index 2 and you call substr(index, 3), which creates the string "Fe3".
Also the standard library usually uses half open ranges, so even if substr took two indices (which, again, it doesn't) you would do substr(index, index+2) to get a two character string.
bool NEXT_LOWER_LETTER = islower(leftSide[index+1]);
You might want to check that index+1 is a valid index. If you don't want to do that manually you might at least switch to using the bounds checked function at() instead of operator[].