Array conversion guidance - c++

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.

Related

Does substr change the position where the find function starts searching?

Does substr change the position where the find function starts searching ?
I have a char * named search_text containing the following text:
ABC_NAME = 'XYZSomeone' AND ABC_CLASS = 'XYZSomething'
I want to display the "ABC_NAME" value from that string.
Here is what I am doing:
std::cout << std::string(search_text).substr ( 12, std::string( search_text ).find ("'", 13 )-1) << std::endl;
My logic in the above in the substr is as follows:
The ABC_NAME value always begins at the 12th character, so start the substring there.
Do a find for the character ' (single quotation mark) from the 13th character onwards, starting from the 13th character (the second argument of the find() function). The resulting number will be the outer bound of the substr.
However, my code prints out the following:
XYZSomeone' AND ABC_C
However, when I try to display the value of the find() function directly, I do get the correct number for the location of the second ' (single quotation mark)
std::cout << std::string( search_text ).find ("'", 13 ) << std::endl;
This prints out:
22
So why is it that the substr is not finding the value of 22 as its second argument ?
It's a rather simple matter to evaluate your expression by hand, seeing how you already verified the result of find:
std::string(search_text).substr ( 12, std::string( search_text ).find ("'", 13 )-1)
std::string("ABC_NAME = 'XYZSomeone' AND ABC_CLASS = 'XYZSomething'").substr ( 12, 22-1)
Now check the documentation for substr: "Returns a substring [pos, pos+count)". The character at position 12 is the 'X' for the name portion, and the character at position 12+21 = 33 is the 'L' from the class portion. So we expect the substring starting at that 'X' and going up to just before that 'L', which is "XYZSomeone' AND ABC_C". Check.
(It is understandable to forget whether substr takes a length or a position at which to end. Different languages do disagree on this. Hence the link to the documentation.)
Unsolicited commentary
Trying to do so much in one line makes your code harder to read and harder to debug. In this case, it also hurts performance. There is no need to convert search_text to a std::string twice.
std::string search_string{search_text};
std::size_t found = search_string.find('\'', 12);
if ( found != std::string::npos )
found -= 12;
std::cout << search_string.substr(12, found) << std::endl;
This cuts the number of times a string is constructed (hence the times the string data is copied) from three to two.
If you are using C++17, you can improve the performance even more by constructing no strings. Just use std::string_view instead of std::string. For this scenario, it has the same member functions taking the same parameters; all you have to change is the type of search_string. This puts the performance on par with C code.
Even better: since string views are so cheap to create, you could even write your code – without a performance hit – so that it doesn't matter whether substr takes a length or takes the past-the-end position.
std::string_view search_string{search_text};
std::string_view ltrimmed = search_string.substr(12);
std::size_t found = ltrimmed.find('\'');
std::cout << ltrimmed.substr(0, found) << std::endl;
Constructive laziness FTW!

Garbage characters in C

Edited question
I understood my mistake in the code I had given in the original question, and the characters I was getting are garbage characters. Although, I still have a few questions about garbage characters in C:
Why can't the character be copied?
Do garbage characters have some pattern? Meaning that can you predict for an empty string what character can come, for an empty integer what will come, and so on.
When a variable is declared, why does it have a garbage character instead of being blank? Is there a specific reason of storing it with a garbage character?
For a string which is not null-terminated, will the same garbage character be printed on every OS? If yes, which one?
Are there the same garbage characters on every OS? Or are they different?
Is there a way to print these characters on the stdout buffer in C / C++?
If you see carefully in the character , there are some characters and numbers in it. Do they represent something?
Is there a list of garbage characters which can be printed in C / C++?
Original Question
Title of original question: Mysterious character output in C
I had come across this code in K & R:
int scanline (char str [], int lim) /* Line will be read in 'str []', while lim is the maximum characters to be read */
{
int c, len, j; /* 'len' will have the length of the read string */
j = 0; /* Initializing 'j' */
for (len = 0; (c = getchar ()) != EOF && c != '\n'; ++len) /* Reading a character one by one, till the user enters '\n', and checking for failure of 'getchar' */
{
if (len < (lim -2)) /* Checking that string entered has not gone beyond it's boundaries. '-2' for '\n' and '\0' */
{
str [j] = c; /* Copying read character into 'string [j]' */
++ j; /* Incrementing 'j' by 1 */
}
}
if (c == '\n') /* Checking if user has finished inputting the line */
{
str [j] = c; /* Copying newline into string */
++j;
++ len;
}
return len; /* Returning number of characters read */
}
In the K & R, it is known as getline, but I made changes, added comments, and thus defined it as scanline. To test this, I made a demo program:
#include <mocl/cancel.h>
int main (int argc, char **argv)
{
int len;
char str [50];
len = scanline (str, 50);
printf ("len = %d\n str = %s\n", len, str);
return 0;
}
The required headers and the function was in my own library, cancel.h. Then when I compiled my program, it was successful. Although, when I ran the executable, I got unexpected output (I cannot type it as I get a character which when I copy, it just gets pasted as 'm'):
The mysterious character is which when I copy, gets copied as the letter m. Also, when I run my program with different inputs, I get different mysterious outputs:
In another case, I get perfect output, just that a blank line is printed:
I had also come across this question, in which the user gets the same symbol.
What have I done till now?
I searched a lot, and I could not find any clue about this character, but if you see carefully, in the second image, I get more characters when I enter "hi this is ashish". One of them is the slash, and one is . But I get another character . I got this link which was showed how to reproduce it, and explained it, although I could not understand. When you run the code given there, you get a lot of characters, and one of them is . Although, even the author of that article could not copy it, and has not posted it. So here's the output:
That was the actual output, as that's not clear, here's a cut out version:
So basically I got to know that both the characters and are extended characters from a string. At that point, I actually figured out what was causing the problem in scanline.
The lines
if (c == '\n') /* Checking if user has finished inputting the line */
{
str [j] = c; /* Copying newline into string */
++j;
++ len;
}
were causing the problems as you were copying a newline into the string. It worked, but I'm not sure why, as doing that was just a guess. I searched but still could not find the reason.
My Questions
How does removing those lines make the program work properly?
What are the characters and ? What are they supposed to do and how did they appear over here?
Are there any more characters like this?
Why can't those characters be copied?
Is it Undefined Behavior?
There's some confusion here regarding the term garbage characters. What it refers to is any byte that resides in a variable that wasn't assigned in some well-defined way. The character A can be a garbage character if it happens to appear in (for example) a block of memory returned by malloc or an uninitialized char variable.
This is distinct from unprintable characters which are any character that does not have a well-defined representation when printed as characters. For example, ASCII codes 0 - 31 and 127 (0 - 1F and 7F hex) are control characters and therefore unprintable. There are also multibyte characters for which a particular terminal may not know how to render them.
To get into your specific questions:
Why can't the character (image) be copied?
As an unprintable character, its screen representation is not well defined. So attempting to copy and paste it from a terminal will yield unexpected results.
Do garbage characters have some pattern? Meaning that can you
predict for an empty string what character can come, for an empty
integer what will come, and so on.
The nature of garbage characters is that their contents are undefined. Trying to predict what uninitialized data will contain is a futile effort. The same piece of code compiled with two different compilers (or the same compiler with different optimization settings) can have completely different contents for any uninitialized data.
The standard doesn't say what values should go there, so implementations are free to handle it however they want. They could chose to leave whatever values happen to be at those memory addresses, they could choose to write 0 to all addresses, they could choose to write the values 0, 1, 2, 3, etc. in sequence. In other words, the contents are undefined.
When a variable is declared, why does it have a garbage character
instead of being blank? Is there a specific reason of storing it with
a garbage character?
Global variables and static local variables are initialized with all bytes zero, which is what the standard dictates. That is something that is done easily at compile time. Local variables on the other hand reside on the stack. So their values are whatever happens to be on the stack at the time the function is called.
Here's an interesting example:
void f1()
{
char str[10];
strcpy(str, "hello");
}
int main()
{
f1();
f1();
return 0;
}
Here is what a particular implementation might do:
The first time f1 is called, the local variable str is uninitialized. Then strcpy is called which copies in the string "hello". This takes up the first 6 bytes of the variable (5 for the string and 1 for the null terminator). The remaining 4 bytes are still garbage. When this functions returns, the memory that the variable str resided at is free to be used for some other purpose.
Now f1 gets called again immediately after the first call. Since no other function was called, the stack for this invocation of f1 happens to sit at the exact same place as the last invocation. So if you were to examine str at this time, you would find it contains h, e, l, l, o, and a null byte (i.e. the string "hello") for the first 6 bytes. But, this string is garbage. It wasn't specifically stored there. If some other function was called before calling f1 a second time, most likely those values would not be there.
Again, garbage means the contents are undefined. The compiler doesn't explicitly put "garbage" (or unprintable characters) in variables.
For a string which is not null-terminated, will the same garbage
character be printed on every OS? If yes, which one?
Here's one of those places you're confusing garbage and unprintable. In your specific case, the garbage character happens to be unprintable, but it doesn't have to be. Here's another example:
void f3()
{
char str1[5], str2[5];
strcpy(str1, "hello");
strcpy(str2, "test");
printf("str1=%s\n", str1);
}
Let's suppose the compiler decides to place str2 immediately after str1 in memory (although it doesn't have to). The first call to strcpy will write the string "hello" into str1, but this variable doesn't have enough room the the null terminating byte. So it gets written to the next byte in memory, which happens to be the first byte of str2. Then when the next call to strcpy runs, it puts the string "test" in str2 but in doing so it overwrites the null terminating byte put there when str1 was written to.
Then when printf gets called, you'll get this as output:
str1=hellotest
When printing str1, printf looks for the null terminator, but there isn't one inside of str1. So it keeps reading until it does. In this case there happens to be another string right after it, so it prints that as well until it finds the null terminator that was properly stored in that string.
But again, this behavior is undefined. A seemingly minor change in this function could result in str2 appearing in memory first. The compiler is free to do as it wishes in the regard, so there's no way to predict what will happen.
Are there the same garbage characters on every OS? Or are they
different?
I believe you're actually referring to unprintable characters in this case. This really depends on the character set of the OS and/or terminal in question. For example, Chinese characters are represented with multiple bytes. If your terminal can't print Chinese characters, you'll see some type of code similar to what you saw for each of the bytes. But if it can, it will display it in a well-defined manner.
Is there a way to print these characters on the stdout buffer in C /
C++?
Not as characters. You can however print out their numerical representations. For example:
void f4()
{
char c;
printf("c=%02hhX\n", (unsigned char)c);
}
The contents of c are undefined, but the above will print whatever value happens to be there in hexadecimal format.
If you see carefully in the character (image),
there are some characters and numbers in it. Do they represent
something?
Some terminals will display unprintable characters by printing a box containing the Unicode codepoint of the character so the reader can know what it is.
Unicode is a standard for text where each character is assigned a numerical code point. Besides the typical set of characters in the ASCII range, Unicode also defines other characters, such as accented letters, other alphabets like Greek, Hebrew, Cyrillic, Chinese, and Japanese, as well as various symbols. Because there are thousands of characters defined by Unicode, multiple bytes are needed to represent them. The most common encoding for Unicode is UTF-8, which allows regular ASCII characters to be encoded with one byte, and other characters to be encoded with two or more bytes as needed.
In this case, the codepoint in question is 007F. This is the DELETE control character, which is typically generated when the Delete key is pressed. Since this is a control character, your terminal is displaying it as a box with the Unicode point for the character instead of attempting to "print" it.
Is there a list of garbage characters which can be printed in C /
C++?
Again, assuming you really mean unprintable characters here, that has more to do with the terminal that's displaying the characters that with the language. Generally, control characters are unprintable, while certain multibyte characters may or may not display properly depending on the font / character set of the terminal.
For starters the function returns incorrect value of len. Let's assume that lim is equal to 2.
In this case in the loop there will be written nothing in the array due to the condition
if (len < (lim -2))
However after the first iteration of the loop len will be increased.
for (len = 0; (c = getchar ()) != EOF && c != '\n'; ++len)
^^^^^
In the second iteration again there will be written nothing in the array diue to the same condition
if (len < (lim -2))
but len will be increased.
for (len = 0; (c = getchar ()) != EOF && c != '\n'; ++len)
^^^^^
Thus nothing will be written in the array but len will be increased until for example the new line character will be encountered.
So the function is invalid. Moreover it is supposed that the function will append the read string with the terminating zero. But this is not done in the function. So you may not output the character array as a string.
The function can be written the following way
int scanline( char str [], int lim )
{
int len = 0;
int c;
while ( len < lim - 1 && ( c = getchar () ) != EOF && c != '\n' )
{
str[len++] = c;
}
if ( len < lim - 1 && c == '\n' ) str[len++] = c;
if ( len < lim ) str[len++] = '\0';
return len;
}

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.

getline() Adding Character to Front of String? -- Actually substr syntax error

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[].

How to remove a character from the string and change data if need it?

I have possible inputs 1M 2M .. 11M and 1Y (M and Y stand for months ) and I want to output "somestring1 somestring2.... and somestring12" note M and Y are removed and the last string is changed to 12
Example: input "11M" "hello" output: hello11
input "1Y" "hello" output: hello1
char * (const char * date, const char * somestr)
{
// just need to output final string no need to change the original string
cout<< finalStr<<endl;
}
The second string is getting output as a whole itself. So no change in its output.
The second string would be output as long as M or Y are encountered. As Stack Overflow discourages providing exact source codes, so I can give you some portion of it. There is a condition to be placed which is up to you to figure out.(The second answer gives that as well)
Code would be somewhat like this.
//Code for first string. Just for output.
for (auto i = 0 ; date[i] != '\0' ; ++i)
{
// A condition comes here.
cout << date[i] ;
}
And note that this is considering you just output the string. Otherwise you can create another string and add up the two or concatenate the existing ones.
is this homework? If not, here's what i'd suggest. (i ask about homework because you may have restrictions, not because we're not here to help)
1) do a find on 'M' in your string (using find), insert a '\0' at that position if one is found (btw i'm assuming you have well formatted input)
2) do a find on 'Y'. if one is found, insert a '\0' at that position. then do an atoi() or stringstream conversion on your string to convert to number. multiply by 12.
3) concatenate your string representation of part 1 or part 2 to your somestr
4) output.
This can probably be done in < 10 lines if i could be bothered.
the a.find('M') part and its checks can be conditional operator, then the conversion/concatenation in two or three lines at most.