My stringNAdd function will duplicate strncat (original). I cannot accept arrays as parameters, but pointers. I wonder if my code right?
Here is the fixed code:
#include <string>
#include <iostream>
using namespace std;
char *stringNAdd(char str1[], char str2[],size_t num);
int main()
{
char dest[50] = "Using strncat function,";
char src[50] = " this part is added and this is ignored";
cout<< strncat(dest, src, 20) << endl;
cout << stringNAdd(dest, src, 20) << endl;
cin.get();
return 0;
}
char *stringNAdd(char str1[], char str2[],size_t num){
size_t str1_len = strlen(str1);
size_t i;
for (i=0; i < num && str2[i] != '\0'; i++)
i==num;
str1[str1_len+i] = str2[i];
str1[str1_len+i] = '\0';
return str1;
}
Output:
Using strncat function, this part is added
Using strncat function, this part is added
The problem is that you don't do the test of both functions in the same conditions: once you've executed strncat(), the dest already contains the longer concatenated version.
The second problem is that dest was already enlarged by 15 chars. It has therefore an initial length of 38 chars + the null terminator before calling stringNAdd(). Adding 15 more chars result in a string of 53 chars plus a null terminator, which is 4 chars longer than your array. So you'll get a buffer overflow, hence memory corruption and undefined behavior.
But all this is related to the testing conditions: your clone works fine.
Suggestions:
Run your functions in distinct blocks, and define your testing variables local to that block:
{
char dest[50] = "Using strncat function,";
char src[50] = " this part is added and this is ignored";
cout<< strncat(dest, src, 15) << endl;
cout << strlen(dest)<<endl;
}
{
char dest[50] = "Using strncat function,";
char src[50] = " this part is added and this is ignored";
cout << stringNAdd(dest, src, 15) << endl;
}
Think of a more secure version of your function, in which you would have an additional argument with the total length of the destination array to prevent these errors. This would increase the security of your code. By the way, this is what Microsoft does with strncat_s().
Finally, you could ask your teacher why he/she still lets you work with cstrings, when there are the so much more convenient and secure std::string, and that he certainly could find more modern exercises with the same pedagogical benefits.
Here is equivalent based on https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/i386.subproj/strncat.c
#include <iostream>
char *strnadd(char *dst, const char *src, size_t n)
{
// abort if source is empty
if (n != 0)
{
// copy pointers
char *d = dst;
const char *s = src;
// find end of destination str
while (*d != 0)
d++;
// start copying chars from source str to the end of destination str
// until either source string ends or number of chars copied
// destination string has to be long enough to accommodate source
do
{
if ((*d = *s++) == 0)
break;
d++;
}
while (--n != 0);
// add null termination
*d = 0;
}
// return the resulting string
return dst;
}
int main()
{
char strCat[50];
char strAdd[50];
strcpy(strCat, "string1");
strcpy(strAdd, "string1");
char const *str2 = "string2";
std::cout << strncat(strCat, str2, 6) << std::endl;
std::cout << strnadd(strAdd, str2, 6) << std::endl;
return 0;
}
Prints:
string1string
string1string
Related
My strncpy function is not working, shows argument of type "cons char" is in compatible with parameter type "char"
And when I call out the prefix function in the main function it says i must have a pointer to function type
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
void prefix(const char s1[], const char s2[], char prefix[]);
int main()
{
char s1[30];
char s2[30];
char prefix[30];
cout << "Enter two sentences to store in two different strings" << endl;
cin.getline(s1, 30);
cin.getline(s2, 30);
prefix(s1, s2, prefix);
}
void prefix(const char a[], const char b[], char prefix[])
{
int size;
if (strlen(a) < strlen(b))
{
size = strlen(a);
}
else if (strlen(a) > strlen(b))
{
size = strlen(b);
}
else
{
size = strlen(a);
}
for (int i = 0; i < size; i++)
{
if (a[i] != b[i])
{
strncpy(a, b, size);
}
}
}
Not sure on your exact error, but it is probably like "error C2064: term does not evaluate to a function taking 3 arguments" or "error: ‘prefix’ cannot be used as a function".
The issue here is you declared a local variable with the name prefix, so it will take precedence over the global function prefix. Some types of variable may be callable (e.g. function pointers, std::function, etc.).
The best solution for that is generally to rename your local, but you can explicitly tell it to use the global scope if desired: ::prefix(s1, s2, prefix);.
There are further errors within the prefix function itself however, as strncpy(a, b, size); tries to copy to a "const" string, which is not allowed, presumably you meant to copy to the prefix string instead, and probably end the loop there.
However, for C++ it would also generally be better to use the std::string type. You can use std::getline(std::cin, my_std_string) to read lines, and prefix = my_std_string.substr(0, i) would be a way to copy part of a string.
For starters this declaration in main
char prefix[30];
hides the function with the same name declared in the global name space.
Either rename the function or the variable or use a qualified name for the function.
This loop
for (int i = 0; i < size; i++)
{
if (a[i] != b[i])
{
strncpy(a, b, size);
}
}
does not make sense and in this call
strncpy(a, b, size);
you are trying to change the constant array pointed to by the pointer a.
And there are many redundant calls of the function strlen.
The function can be declared and defined the following way as it is shown in the demonstrative program below.
#include <iostream>
char * common_prefix( const char s1[], const char s2[], char prefix[] )
{
char *p = prefix;
for ( ; *s1 != '\0' && *s1 == *s2; ++s1, ++s2 )
{
*p++ = *s1;
}
*p = '\0';
return prefix;
}
int main()
{
const size_t N = 30;
char s1[N];
char s2[N];
char prefix[N];
std::cout << "Enter two sentences to store in two different strings" << '\n';
std::cin.getline( s1, N );
std::cin.getline( s2, N );
std::cout << "The common prefix is \"" << common_prefix( s1, s2, prefix )
<< "\"\n";
return 0;
}
Its output might look like
Enter two sentences to store in two different strings
Hello C#
Hello C++
The common prefix is "Hello C"
I just started learning about pointers so I'd thought I'd share what I'm trying to do. Of a character array (let's call it c and it's equal to "Hello"), I'm trying to return the memory location of a certain element. Say the memory of location of 'l'. Here's what I have so far:
#include <iostream>
using namespace std;
char* str_char(char* c_ptr, char c);
int main()
{
char *c = "Hello";
cout << str_char(c, 'l') << endl;
return 0;
}
char* str_char(char* c_ptr, char c)
{
for (int i = 0; i < sizeof(c_ptr); i++)
{
if (*(c_ptr + i) == c)
{
return (c_ptr + i);
break;
}
}
}
After I use the function, it outputs "llo".
You are on the right track. However, there are a few things that are not right.
Use of sizeof(c_ptr) is not right. It works for your case due to happy coincidence.
sizeof(c_ptr) is equal to sizeof(char*). It is not equal to the size of the array from the calling function.
There is a missing return statement at end of the function -- the case where c is not found in c_ptr.
There is no need of the break; after the return;.
Also, you can simplify the function a little bit.
Here's an updated version:
char* str_char(char* c_ptr, char c)
{
for (char* cp = c_ptr; *cp != '\0'; ++cp )
{
if (*cp == c)
{
return cp;
}
}
return nullptr;
}
The earlier answer has covered the bugs, so I'll just answer the actual question...
The function does return the location of an array element.
The << operator treats every char* as a pointer to a zero-terminated string, and outputting the result of str_char works exactly like outputting c; it prints every character after that location until it encounters a zero.
If you want to output the value of the location itself, you need to cast it to a different type:
cout << static_cast<void*>(str_char(c, 'l')) << endl;
as << has an overload for void* that outputs the address itself.
R Sahu gave you answer that is slightly modified version of your function . That is legal code, but that is basicly a C code, except use of nullptr. Returning nullptr is non-canon and if nupllptr will be returned, what << operator would do? That's undefined behavior.
it is often agreed pattern to leave iterator (pointer) pointing at end of line (at the terminating zero) to avoid crash you may cause by returning nullptr.
char* str_char(char* c_ptr, char c)
{
char* cp = c_ptr;
for (; *cp != '\0'; ++cp )
{
if (*cp == c)
{
return cp;
}
}
return cp;
// if cp was declared inside scope , we can't retirn it's value
}
Normally you do not need to write own string functions.. bth C library and C++ got them already covered. C++ got set of abstract algorithmic functions, in your case a strchr, find or find_if is prudent:
#include <algorithm>
#include <iostream>
using std::cout;
int main()
{
char *c = "Hello";
cout << std::strchr(c, 'l') << '\n';
// with pointer to null-terminated string, strlen searches
// for zero char and returns the count of characters before it
cout << std::find(c, c + strlen(c), 'l') << '\n';
// with declared array we can use std:begin and std::end
char carr[] = "Hello";
cout << std::find(std::begin(carr),std::end(carr) , 'l') << '\n';
// with pointer to null-terminated string a lambda expression
// can be used to stop at 0 as well as at first key
const char key = 'l';
cout << std::find_if(c, c + strlen(c),[=](const char& item)
{
return (item == key) || (item == '\0');
}) << '\n';
return 0;
}
An std::vector or ::array or other containers can be used with those templates as well.
The <algorithms> header would save tons of time you need to debug your custom-tailored functions for search, iteration, etc.
P.S. cout and cin deal with char and char* in special way.. char* is always pointer at string, char is always a character, not a number, so casts are required if you mean otherwise.
I tried to write a script that removes extra white spaces but I didn't manage to finish it.
Basically I want to transform abc sssd g g sdg gg gf into abc sssd g g sdg gg gf.
In languages like PHP or C#, it would be very easy, but not in C++, I see. This is my code:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <cstring>
#include <unistd.h>
#include <string.h>
char* trim3(char* s) {
int l = strlen(s);
while(isspace(s[l - 1])) --l;
while(* s && isspace(* s)) ++s, --l;
return strndup(s, l);
}
char *str_replace(char * t1, char * t2, char * t6)
{
char*t4;
char*t5=(char *)malloc(10);
memset(t5, 0, 10);
while(strstr(t6,t1))
{
t4=strstr(t6,t1);
strncpy(t5+strlen(t5),t6,t4-t6);
strcat(t5,t2);
t4+=strlen(t1);
t6=t4;
}
return strcat(t5,t4);
}
void remove_extra_whitespaces(char* input,char* output)
{
char* inputPtr = input; // init inputPtr always at the last moment.
int spacecount = 0;
while(*inputPtr != '\0')
{
char* substr;
strncpy(substr, inputPtr+0, 1);
if(substr == " ")
{
spacecount++;
}
else
{
spacecount = 0;
}
printf("[%p] -> %d\n",*substr,spacecount);
// Assume the string last with \0
// some code
inputPtr++; // After "some code" (instead of what you wrote).
}
}
int main(int argc, char **argv)
{
printf("testing 2 ..\n");
char input[0x255] = "asfa sas f f dgdgd dg ggg";
char output[0x255] = "NO_OUTPUT_YET";
remove_extra_whitespaces(input,output);
return 1;
}
It doesn't work. I tried several methods. What I am trying to do is to iterate the string letter by letter and dump it in another string as long as there is only one space in a row; if there are two spaces, don't write the second character to the new string.
How can I solve this?
There are already plenty of nice solutions. I propose you an alternative based on a dedicated <algorithm> meant to avoid consecutive duplicates: unique_copy():
void remove_extra_whitespaces(const string &input, string &output)
{
output.clear(); // unless you want to add at the end of existing sring...
unique_copy (input.begin(), input.end(), back_insert_iterator<string>(output),
[](char a,char b){ return isspace(a) && isspace(b);});
cout << output<<endl;
}
Here is a live demo. Note that I changed from c style strings to the safer and more powerful C++ strings.
Edit: if keeping c-style strings is required in your code, you could use almost the same code but with pointers instead of iterators. That's the magic of C++. Here is another live demo.
Here's a simple, non-C++11 solution, using the same remove_extra_whitespace() signature as in the question:
#include <cstdio>
void remove_extra_whitespaces(char* input, char* output)
{
int inputIndex = 0;
int outputIndex = 0;
while(input[inputIndex] != '\0')
{
output[outputIndex] = input[inputIndex];
if(input[inputIndex] == ' ')
{
while(input[inputIndex + 1] == ' ')
{
// skip over any extra spaces
inputIndex++;
}
}
outputIndex++;
inputIndex++;
}
// null-terminate output
output[outputIndex] = '\0';
}
int main(int argc, char **argv)
{
char input[0x255] = "asfa sas f f dgdgd dg ggg";
char output[0x255] = "NO_OUTPUT_YET";
remove_extra_whitespaces(input,output);
printf("input: %s\noutput: %s\n", input, output);
return 1;
}
Output:
input: asfa sas f f dgdgd dg ggg
output: asfa sas f f dgdgd dg ggg
Since you use C++, you can take advantage of standard-library features designed for that sort of work. You could use std::string (instead of char[0x255]) and std::istringstream, which will replace most of the pointer arithmetic.
First, make a string stream:
std::istringstream stream(input);
Then, read strings from it. It will remove the whitespace delimiters automatically:
std::string word;
while (stream >> word)
{
...
}
Inside the loop, build your output string:
if (!output.empty()) // special case: no space before first word
output += ' ';
output += word;
A disadvantage of this method is that it allocates memory dynamically (including several reallocations, performed when the output string grows).
There are plenty of ways of doing this (e.g., using regular expressions), but one way you could do this is using std::copy_if with a stateful functor remembering whether the last character was a space:
#include <algorithm>
#include <string>
#include <iostream>
struct if_not_prev_space
{
// Is last encountered character space.
bool m_is = false;
bool operator()(const char c)
{
// Copy if last was not space, or current is not space.
const bool ret = !m_is || c != ' ';
m_is = c == ' ';
return ret;
}
};
int main()
{
const std::string s("abc sssd g g sdg gg gf into abc sssd g g sdg gg gf");
std::string o;
std::copy_if(std::begin(s), std::end(s), std::back_inserter(o), if_not_prev_space());
std::cout << o << std::endl;
}
You can use std::unique which reduces adjacent duplicates to a single instance according to how you define what makes two elements equal is.
Here I have defined elements as equal if they are both whitespace characters:
inline std::string& remove_extra_ws_mute(std::string& s)
{
s.erase(std::unique(std::begin(s), std::end(s), [](unsigned char a, unsigned char b){
return std::isspace(a) && std::isspace(b);
}), std::end(s));
return s;
}
inline std::string remove_extra_ws_copy(std::string s)
{
return remove_extra_ws_mute(s);
}
std::unique moves the duplicates to the end of the string and returns an iterator to the beginning of them so they can be erased.
Additionally, if you must work with low level strings then you can still use std::unique on the pointers:
char* remove_extra_ws(char const* s)
{
std::size_t len = std::strlen(s);
char* buf = new char[len + 1];
std::strcpy(buf, s);
// Note that std::unique will also retain the null terminator
// in its correct position at the end of the valid portion
// of the string
std::unique(buf, buf + len + 1, [](unsigned char a, unsigned char b){
return (a && std::isspace(a)) && (b && std::isspace(b));
});
return buf;
}
for in-place modification you can apply erase-remove technic:
#include <string>
#include <iostream>
#include <algorithm>
#include <cctype>
int main()
{
std::string input {"asfa sas f f dgdgd dg ggg"};
bool prev_is_space = true;
input.erase(std::remove_if(input.begin(), input.end(), [&prev_is_space](unsigned char curr) {
bool r = std::isspace(curr) && prev_is_space;
prev_is_space = std::isspace(curr);
return r;
}), input.end());
std::cout << input << "\n";
}
So you first move all extra spaces to the end of the string and then truncate it.
The great advantage of C++ is that is universal enough to port your code to plain-c-static strings with only few modifications:
void erase(char * p) {
// note that this ony works good when initial array is allocated in the static array
// so we do not need to rearrange memory
*p = 0;
}
int main()
{
char input [] {"asfa sas f f dgdgd dg ggg"};
bool prev_is_space = true;
erase(std::remove_if(std::begin(input), std::end(input), [&prev_is_space](unsigned char curr) {
bool r = std::isspace(curr) && prev_is_space;
prev_is_space = std::isspace(curr);
return r;
}));
std::cout << input << "\n";
}
Interesting enough remove step here is string-representation independent. It will work with std::string without modifications at all.
I have the sinking feeling that good ol' scanf will do (in fact, this is the C school equivalent to Anatoly's C++ solution):
void remove_extra_whitespaces(char* input, char* output)
{
int srcOffs = 0, destOffs = 0, numRead = 0;
while(sscanf(input + srcOffs, "%s%n", output + destOffs, &numRead) > 0)
{
srcOffs += numRead;
destOffs += strlen(output + destOffs);
output[destOffs++] = ' '; // overwrite 0, advance past that
}
output[destOffs > 0 ? destOffs-1 : 0] = '\0';
}
We exploit the fact that scanf has magical built-in space skipping capabilities. We then use the perhaps less known %n "conversion" specification which gives us the amount of chars consumed by scanf. This feature frequently comes in handy when reading from strings, like here. The bitter drop which makes this solution less-than-perfect is the strlen call on the output (there is no "how many bytes have I actually just written" conversion specifier, unfortunately).
Last not least use of scanf is easy here because sufficient memory is guaranteed to exist at output; if that were not the case, the code would become more complex due to buffering and overflow handling.
Since you are writing c-style, here's a way to do what you want.
Note that you can remove '\r' and '\n' which are line breaks (but of course that's up to you if you consider those whitespaces or not).
This function should be as fast or faster than any other alternative and no memory allocation takes place even when it's called with std::strings (I've overloaded it).
char temp[] = " alsdasdl gasdasd ee";
remove_whitesaces(temp);
printf("%s\n", temp);
int remove_whitesaces(char *p)
{
int len = strlen(p);
int new_len = 0;
bool space = false;
for (int i = 0; i < len; i++)
{
switch (p[i])
{
case ' ': space = true; break;
case '\t': space = true; break;
case '\n': break; // you could set space true for \r and \n
case '\r': break; // if you consider them spaces, I just ignore them.
default:
if (space && new_len > 0)
p[new_len++] = ' ';
p[new_len++] = p[i];
space = false;
}
}
p[new_len] = '\0';
return new_len;
}
// and you can use it with strings too,
inline int remove_whitesaces(std::string &str)
{
int len = remove_whitesaces(&str[0]);
str.resize(len);
return len; // returning len for consistency with the primary function
// but u can return std::string instead.
}
// again no memory allocation is gonna take place,
// since resize does not not free memory because the length is either equal or lower
If you take a brief look at the C++ Standard library, you will notice that a lot C++ functions that return std::string, or other std::objects are basically a wrapper to a well written extern "C" function. So don't be afraid to use C functions in C++ applications, if they are well written and you can overload them to support std::strings and such.
For example, in Visual Studio 2015, std::to_string is written exactly like this:
inline string to_string(int _Val)
{ // convert int to string
return (_Integral_to_string("%d", _Val));
}
inline string to_string(unsigned int _Val)
{ // convert unsigned int to string
return (_Integral_to_string("%u", _Val));
}
and _Integral_to_string is a wrapper to a C function sprintf_s
template<class _Ty> inline
string _Integral_to_string(const char *_Fmt, _Ty _Val)
{ // convert _Ty to string
static_assert(is_integral<_Ty>::value,
"_Ty must be integral");
char _Buf[_TO_STRING_BUF_SIZE];
int _Len = _CSTD sprintf_s(_Buf, _TO_STRING_BUF_SIZE, _Fmt, _Val);
return (string(_Buf, _Len));
}
Well here is a longish(but easy) solution that does not use pointers.
It can be optimized further but hey it works.
#include <iostream>
#include <string>
using namespace std;
void removeExtraSpace(string str);
int main(){
string s;
cout << "Enter a string with extra spaces: ";
getline(cin, s);
removeExtraSpace(s);
return 0;
}
void removeExtraSpace(string str){
int len = str.size();
if(len==0){
cout << "Simplified String: " << endl;
cout << "I would appreciate it if you could enter more than 0 characters. " << endl;
return;
}
char ch1[len];
char ch2[len];
//Placing characters of str in ch1[]
for(int i=0; i<len; i++){
ch1[i]=str[i];
}
//Computing index of 1st non-space character
int pos=0;
for(int i=0; i<len; i++){
if(ch1[i] != ' '){
pos = i;
break;
}
}
int cons_arr = 1;
ch2[0] = ch1[pos];
for(int i=(pos+1); i<len; i++){
char x = ch1[i];
if(x==char(32)){
//Checking whether character at ch2[i]==' '
if(ch2[cons_arr-1] == ' '){
continue;
}
else{
ch2[cons_arr] = ' ';
cons_arr++;
continue;
}
}
ch2[cons_arr] = x;
cons_arr++;
}
//Printing the char array
cout << "Simplified string: " << endl;
for(int i=0; i<cons_arr; i++){
cout << ch2[i];
}
cout << endl;
}
I don't know if this helps but this is how I did it on my homework. The only case where it might break a bit is when there is spaces at the beginning of the string EX " wor ds " In that case, it will change it to " wor ds"
void ShortenSpace(string &usrStr){
char cha1;
char cha2;
for (int i = 0; i < usrStr.size() - 1; ++i) {
cha1 = usrStr.at(i);
cha2 = usrStr.at(i + 1);
if ((cha1 == ' ') && (cha2 == ' ')) {
usrStr.erase(usrStr.begin() + 1 + i);
--i;//edit: was ++i instead of --i, made code not work properly
}
}
}
I ended up here for a slighly different problem. Since I don't know where else to put it, and I found out what was wrong, I share it here. Don't be cross with me, please.
I had some strings that would print additional spaces at their ends, while showing up without spaces in debugging. The strings where formed in windows calls like VerQueryValue(), which besides other stuff outputs a string length, as e.g. iProductNameLen in the following line converting the result to a string named strProductName:
strProductName = string((LPCSTR)pvProductName, iProductNameLen)
then produced a string with a \0 byte at the end, which did not show easily in de debugger, but printed on screen as a space. I'll leave the solution of this as an excercise, since it is not hard at all, once you are aware of this.
Ok so this code does compile, and it does run, but it does NOT give me the correct output for EITHER the original or reverse array, just gibberish. I spent the last 4 hours trying to see where I went wrong (it wasn't working at all before and now that I got it to at least output what SHOULD be a C-string, i get gibberish). Someone please help me see where I went wrong.
#include <iostream>
#include <cstring>
using namespace std;
char* getInput();
char* getReverse(char[], int);
void displayResults(char *, char *);
const int MAX_SIZE = 21;
int main()
{
//program to create a c-string and then output the reverse order
char *original;
char *reverse;
original = getInput();
int originalSize = strlen(original);
reverse = getReverse(original, originalSize);
displayResults(original, reverse);
return 0;
}
/***************************************************
Definition of function- getInput: *
prompts the user to enter in a line of text to a *
max amount of characters. Returns a pointer to the *
C-string array. *
****************************************************/
char* getInput()
{
char *originalptr;
char original[MAX_SIZE];
cout << "Enter a word or line of text up to a max of 20 characters\nand will have it output in reverse!" << endl;
cin.getline(original, MAX_SIZE);
originalptr = original;
return originalptr;
}
char* getReverse(char *reverseThis, int size)
{
char* reverseOutput;
char reverse[MAX_SIZE];
int counter = 0;
while(*reverseThis != '\0')
{
reverse[counter] = *(reverseThis + (size - counter));
reverseThis++;
counter++;
}
reverseOutput = reverse;
return reverseOutput;
}
void displayResults(char *original, char *reverse)
{
cout << "\nYou originally entered: " << original << endl;
cout << "In reverse order: " << reverse << endl;
}
In 'getReverse' you are allocating the variable 'reverse' on the STACK meaning the data will be GONE WHEN THE FUNCTION RETURNS, no matter how many pointers reference that data.
I would declare 'reverse' in main with 'char reverse[MAX_SIZE];', then have the function take a parameter 'char reverse[]', which the function would then modify.
You are returning a pointer to a local array. The array original is destroyed after the function getInput exits. So original in main is pointing at something which no longer exists, garbage in other words. getReverse has exactly the same problem.
One way to solve this is to declare the arrays in main, and pass pointers to those arrays to the getInput and getReverse functions, for instance.
int main()
{
//program to create a c-string and then output the reverse order
char original[MAX_SIZE];
char reverse[MAX_SIZE];
getInput(original);
int originalSize = strlen(original);
getReverse(original, originalSize, reverse);
displayResults(original, reverse);
return 0;
}
void getInput(char* original)
{
cout << "Enter a word or line of text up to a max of 20 characters\nand will have it output in reverse!" << endl;
cin.getline(original, MAX_SIZE);
}
// etc
You are wasting too much char* s and data. Why not try this :
(I have not tested the code, but it must work ,probably with minor fixes,if any.)
#define MAXSIZE 20
void getinput(char *in)
{
cin.getline(in,MAXSIZE);
return;
}
void reverse(char *in);
{
int len=strlen(in);
char *store=in;
while(int i=0;i<len/2;i++)
{
char temp;
temp=*in;
*in=*(store+len);
in++;len--;
}
return;
}
int main()
{
char data[MAXSIZE];
getinput(data);
cout<<"Original :"<<data;
reverse(data);
cout<<"reverse"<<data;
}
I wrote this code to reverse strings. It works well, but when I enter short strings like "american beauty," it actually prints "ytuaeb nacirema2." This is my code. I would like to know what is wrong with my code that prints a random 2 at the end of the string. Thanks
// This program prompts the user to enter a string and displays it backwards.
#include <iostream>
#include <cstdlib>
using namespace std;
void printBackwards(char *strPtr); // Function prototype
int main() {
const int SIZE = 50;
char userString[SIZE];
char *strPtr;
cout << "Please enter a string (up to 49 characters)";
cin.getline(userString, SIZE);
printBackwards(userString);
}
//**************************************************************
// Definition of printBackwards. This function receives a *
// pointer to character and inverts the order of the characters*
// within it. *
//**************************************************************
void printBackwards(char *strPtr) {
const int SIZE = 50;
int length = 0;
char stringInverted[SIZE];
int count = 0;
char *strPtr1 = 0;
int stringSize;
int i = 0;
int sum = 0;
while (*strPtr != '\0') {
strPtr++; // Set the pointer at the end of the string.
sum++; // Add to sum.
}
strPtr--;
// Save the contents of strPtr on stringInverted on inverted order
while (count < sum) {
stringInverted[count] = *strPtr;
strPtr--;
count++;
}
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
cout << stringInverted << endl;
}
Thanks.
Your null termination is wrong. You're using == instead of =. You need to change:
stringInverted[count] == '\0';
into
stringInverted[count] = '\0';
// Add '\0' at the end of stringSize
stringInverted[count] == '\0';
Should use = here.
What is wrong with your code is that you do not even use strlen for counting the length of the string and you use fixed size strings (no malloc, or, gasp new[]), or the std::string (this is C++)! Even in plain C, not using strlen is always wrong because it is hand-optimized for the processor. What is worst, you have allocated the string to be returned (stringInverted) from the stack frame, which means when the function exits, the pointer is invalid and any time the code "works" is purely accidental.
To reverse a string on c++ you do this:
#include <iostream>
#include <string>
int main() {
std::string s = "asdfasdf";
std::string reversed (s.rbegin(), s.rend());
std::cout << reversed << std::endl;
}
To reverse a string in C99 you do this:
char *reverse(const char *string) {
int length = strlen(string);
char *rv = (char*)malloc(length + 1);
char *end = rv + length;
*end-- = 0;
for ( ; end >= rv; end --, string ++) {
*end = *string;
}
return rv;
}
and remember to free the returned pointer after use. All other answers so far are blatantly wrong :)