Pointer retaining string - c++

So I wrote a code that inputs a word, takes it's first letter and puts it at the end of the word( eg. "egg" will be "gge", and if we do the same process again it will be "geg" and then finally back to "egg")
I want to do this process only 1 time. And I want to use a pointer to memorize the initial value of the word, that is egg, and then the string has to memorize "gge".
This is the code:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[100],aux,*P;
int p=1,i,n,k,j;
cin.get(s,100);
i=0;
while(i>=0)
{
P=s; //this is the pointer that SHOULD memorize "egg"
aux=s[0];
for(j=1; j<=n; j++) s[j-1]=s[j];
s[n]=aux;//until here it does the letter thing
break;
}
cout<<P<<endl<<s;//now here the pointer P should be "egg" and the string s should be "gge"
//but the program prints out "gge" and "gge".
return 0;
}
What am I doing wrong and how am I supposed to do what I want?

What am I doing wrong and how am I supposed to do what I want?
You seem to have misunderstood what a pointer is.
A pointer is a variable that points to something else. In this case
char s[100];
char *P = s;
P points to the first character element of s. This is the same pointer that s decays to in many contexts.
You still only have one array to store 100 characters. You just have two identifiers for that array, because you can reach it via either s or P.
If you mutate that array in place from "egg" to "gge" or whatever, P still just points to the same array it did originally. It didn't save a copy of anything but the location (address) and that isn't what changed.
If I can take two roads to get to your blue house, and you repaint the house green, one of the roads doesn't still lead to the original blue house. That isn't how roads work, or how houses work, or how pointers work.
You want somewhere to store the original 3 or 4 characters, which means you want another char array, or better a std::string. This will make a copy of the characters you care about before you change them.
The minimal working change is probably
// P = s <-- just stores the location
P = strdup(s); // <- copies the contents
but do note you should free(P) at some point after you're done with it. Switching to std::string is really much easier.
Simple example of using std::string value semantics to do the copying:
#include <string>
#include <algorithm>
#include <iostream>
// source is a copy of the string passed
std::string rotate_left(std::string source, size_t offset = 1)
{
std::rotate(source.begin(), source.begin()+offset, source.end());
return source;
}
int main()
{
std::string original{"eggsoup"};
// for interactive use: getline(std::cin, original);
std::string rotated = rotate_left(original);
std::cout << original << '\n' << rotated << '\n';
}

This is called rotating the string.
It's not clear why you have decided to use a pointer for this. A pointer is not a string. A pointer doesn't "contain" its own information*. A pointer points to some piece of information. Here you're making a pointer that points to the original string, and then you alter that string … but your pointer is still just pointing to that same, altered string. The pointer has no knowledge of what form the string used to take, only where it is.
If you want to store a copy of the original string, you have to literally do that, either by copying its elements into a second char array, or by switching to std::string because it's 2018. 😀
* Well, obviously it does; it contains the address of the thing it points to, which in itself is "information". But it's not the information you wanted.
If you really want to use a pointer, you can actually get the expected outcome using them, but not in the way that you're expecting (i.e. not by storing a copy of the string). Since you know you have rotated the string n times, and you know where it starts (that's P!) and you know how long it is (that's n, although you currently aren't setting that, which is a bug), you can do some mathematics to output the original form of the string just by navigating its current form in a different order.
const char* startOfString = &s[0];
const size_t lengthOfString = strlen(s);
const size_t numberOfRotations = 1;
// ... do your rotation here
// Now we can still print the original form, char by char, using MATHS!
for (size_t index = 0; index < lengthOfString; index++)
{
const size_t adjustedIndex = (index + lengthOfString - numberOfRotations) % lengthOfString;
std::cout << startOfString[adjustedIndex];
}
(live demo)
But, then, you may as well have "performed" (or pretended to perform) the actual rotation in this manner in the first place, too.
Or just print the string when you get it, before you rotate it.

Related

How to reverse a string using pointers?

How to reverse a string using pointers. I don't understand any of the answers online. I need it to be explained really slowly.
For an assignment, I need to use pointers to reverse a string (and to use that to test if something is a palindrome), and I cannot for the life of me understand any of the answers to similar questions online. In this question, for instance, the top answer is:
void rev_string(char *str)
{
char *p = str, *s = str + strlen(str) - 1;
while (p < s) {
char tmp = *p;
*p++ = *s;
*s-- = tmp;
}
}
This barely makes sense to me.
First of all, why is the input a char when we're looking to reverse a string? The * marks it as a pointer as well, right? Why is the input a pointer when we're looking to reverse a string?
I understand the first line of code with the variable initialization is meant to set pointer p equal to the start of the string, and pointer s to the tail of the string, but why?
I get the feeling that *p++ and *s-- are supposed to go to the next letter or the previous letter of the string, respectively, but why does that work?
Please assist.
I think the main problem with your example is that the coding style is bad.
Good code is readable (another good lesson to learn today).
The use of prefix and postfix ++, -- in the original code
while correct do also not help in making clear what the code is doing.
Another lesson is not to sacrifice readability for premature optimization like that. Compilers are smart and can optimize quite a bit of your input.
#include <iostream>
void reverse(char* input)
{
const std::size_t offset_of_last_character = strlen(input) - 1;
char* begin_pointer = &input[0]; // front_pointer now contains address of first character in string
char* end_pointer = &input[offset_of_last_character]; // end_pointer now contains address of last character in the string
while (begin_pointer < end_pointer) // as long as pointers don't cross-over in memory continue
{
// swap the characters pointed to
// first iteration this will be first and last character,
// second iteration this will be the second and the character and last but one character, etc...
std::swap(*begin_pointer, *end_pointer);
++begin_pointer; // move one address up in memory, this is where the next character is found
--end_pointer; // move on address down in memory, this is where the previous character is found
}
}
int main()
{
char input[] = "!dlrow olleH";
reverse(input);
std::cout << input;
return 0;
}
First of all, why is the input a char when we're looking to reverse a string? The * marks it as a pointer as well, right? Why is the input a pointer when we're looking to reverse a string?
The code is C. A string in C is a NUL-terminated array of chars. Thus a "hello" string is indeed a char str[6] = {'h', 'e', 'l', 'l', 'o', (char)0x00}; How do you pass this to a function? You pass the pointer char * to the very first element of a string.
I understand the first line of code with the variable initialization is meant to set pointer p equal to the start of the string, and pointer s to the tail of the string, but why?
Because the function considers the input pointer to point at the start of a char array with the aforementioned properties. Pointers p and s are meant to point inside the array. Pointer p is initially set at the start of the array, pointer s is initially set at a strlen(str) - 1 offset into the array. The offset is exactly where the last character in the array is.
I get the feeling that *p++ and *s-- are supposed to go to the next letter or the previous letter of the string, respectively, but why does that work?
The feeling is correct. These two are just pointers inside the array, they just travel along array's elements. This syntax used here says: "dereference the pointer, and right after the expression is done (may think compiler sees ;) increment/decrement the pointer".
To finish it up. I really recommend the "C Programming Language" book to read. Strings in C, passing arrays to functions, and pointer arithmentics are what the given code is about.

How to flip a Char array with pointers in C++

the function of my program is to simply have a char array with a first and last name, and switch it so it is last name first name.
(Tom,Cruise --> Cruise,Tom). I have just started using pointers and cannot find a way to rearrange the Char array. I have tried for-loops and while loops but I don't really know how to tackle this problem. I don't necessarily need hard code. Even a suggestion would help get me moving in the right direction. I am not getting any errors. Due to requirements I am unable to modify the main function whatsoever and the function header has to be
char *LastFirstName(char *ptr).
Thanks
#include <iostream>
using namespace std;
char *LastFirstName(char *name);
int main()
{
char name[41];
char *ptr;
// Force user to enter full name, if not entered, ask again
while (true)
{
name[0] = '\0';
cout << "Enter your full name: ";
cin.getline(name, 40);
if (name[0] == '\0')
cout << "Name not entered. Re-enter full name.\n";
else
break;
}
cout << "Before calling function LastFirstName(), name is " << name
<<endl;
ptr = LastFirstName(name);
cout << "After calling function LastFirstName(), name is " << ptr << endl;
system("pause");
return 0;
}
// This is where I am havinbg trouble
char *LastFirstName(char *ptr) {
char *p;
p = ptr;
int len = strlen(ptr);
return ptr;
}
You can use this function:
void LastFirstName(char* first_last_name)
{
char first_name[41] = {0};
char last_name[41] = {0};
// Dunno what is your separator ' ' or ','...
char* sep_index = strchr(first_last_name, ','); // This return the first index of ','.
*sep_index = '\0';
strcpy(first_name, first_last_name); // Lets copy first name.
strcpy(last_name, first_last_name + strlen(first_last_name) + 1); // Lets copy last name.
// Lets copy it in reverse order.
strcpy(first_last_name, last_name);
strcpy(first_last_name + strlen(last_name) + 1, first_name);
first_last_name[strlen(last_name)] = ',';
}
Notice that we don't need to return char* because the function is modifying the array it received as argument, so actually name array is now reversed as requested.
ptr = LastFirstName(name); this doesn't really do anything. I mean, after that both ptr and name point to the same area in the memory... so it's pretty pointless (got it? 'pointless'... k, won't do that again.) to do that (the LastFirstName works on the memory pointed by name, which means that after the function ends name will hold the results.
It would be easier to ask for the name, and then last name, then just swap the addresses that the pointers are pointing to... but that would be no-fun and we wouldn't learn anything from that, would we? (I'm just saying that there's another option. Don't get me wrong)
Now let's get to the coding. Since returning pointer in this case doesn't make sense (unless you want to have 2 arrays, each with different order), so let's change the function's declaration into void LastFirstName(char *ptr).
Now we need to know where the name ends. We have to find the first occurence of a space (or any other character you want the two to be separated with), which is easily done with strchr(char*, int) function.
After that, since the name and last name doesn't need to be the same length we can't just swap their letters, it would be handy to just copy the name somewhere (another array), then override the name with the last name, copy the name right after that, and terminate with '\0'.
The code would look something like that (not tested, use with care):
void LastFirstName(char *ptr)
{
char name[41], ptr2(ptr);
const size_t nameLen(strchr(ptr, ' ')); // Change the space for whatever you want. btw, I used constructor here.
strncpy(name, ptr, nameLen); // Copy the name from "ptr" to "name"
ptr += nameLen+1; // Move pointer to the first character of the last name
/* We could use some pre-made functions to avoid doing the for loop below
but that's not the point in learning, is it? */
for(size_t i(strlen(ptr) - nameLen - 1); i>0; --i) // I also used constructor here
{
*ptr2 = *ptr;
++ptr2;
++ptr;
}
*ptr2 = ' ' // Again, you can change it to whatever you want
++ptr2; // it's better to do it that way - compiles into faster code
strncpy(ptr2, name, nameLen); // let's copy the name back into our array
ptr2 += nameLen; // Move the pointer to the end and append '\0'
*ptr2 = '\0'; /* We would have passed nameLen+1 previously (and now)
to get the null terminator copied within the strncpy, but it's better
that way - it helps you to understand what happens behind the
courtain. */
return; // unnecessary, but it's a good habit imho
}
/**
Since you pass a copy of pointer, and not a pointer itself, to a function,
you don't have to worry about getting it back to the position it was before.
*/
As you can see, I also made use of the strncpy(char*, char*, size_t) function.
Oh, and size_t is just a unsigned integer, used to express size in memory. It doesn't really differ from any other unsigned integer. It's just an alias.
And a little tip at the end: use C-style arrays (char array[]), wherever you can. Since their size is known at compile time the compiler can optimise it better. Not to mention that dynamic allocation (which I believe you will learn about next, that's what we use pointers for, mostly... left? I mean, right?) is just slower.
Hope I helped.

How to use multidimensional char or string arrays in a loop

I'm so new to C++ and I just can't figure out how to use any multidimesional arrays. I want to do something like that:
input number of product: number; //the products' name can be 7 with NULL char. (max 6)
char arr[number][7];
That works. But when I want to do that in a for loop(i):
cin>>arr[i][7];
and I don't know what the hell is compiler doing?
I just want that:
arr[0][7]=apple;
arr[1][7]=orange;
So please how can I do that?
#include <string>
#include <vector>
Since everybody is recommending it, I thought I'd sketch the options for you.
Note that you would have gotten this kind of answer in 10 milli-seconds by 3 different persons, if you had supplied a short, working sample code snippet (translating code 1:1 is more efficient than 'thinking up' examples that you might recognize)
Here you go:
std::vector<std::string> strings
strings.push_back("apple");
strings.push_back("banana");
// or
std::string s;
std::cin >> s; // a word
strings.push_back(s);
// or
std::getline(std::cin, s); // a whole line
strings.push_back(s);
// or:
// add #include <iterator>
// add #include <algorithm>
std::copy(std::istream_iterator<std::string>(std::cin),
std::istream_iterator<std::string>(),
std::back_inserter(strings));
Direct addressing is also possible:
std::vector<std::string> strings(10); // 10 empty strings
strings[7] = "seventh";
Edit in response to comments:
const char* eighth = "eighth";
if (strings[7] != eighth)
{
// not equal
}
// If you really **must** (read, no you don't) you can get a const char* for the string:
const char* sz = strings[7].c_str(); // warning:
// invalidated when `strings[7]` is modified/destructed
Unless you have a real reason (which you mustn't hide from us), make as Björn says and use a vector of strings. You can even do away with the initial request for the total size:
#include <string>
#include <vector>
#include <iostream>
std::vector<std::string> fruits;
std::string line;
while (std::getline(std::cin, line))
{
fruits.push_back(line);
}
Let's test:
std::cout << "You entered the following items:\n";
for (auto const & f : fruits) std::cout << "* " << f << "\n";
Because arr[i][7] is a char, and in fact one past the last element, which means you may get memory access error.
What you want to do maybe cin>>arr[i];.
How ever, this is not a very good idea, as you cannot control how many characters are read from input, which will easily cause memory overrun.
The easy way would be using std::vector<std::string> as others have suggested.
strcpy(&arr[0], "apple");
strcpy(&arr[1], "orange");
but for C++ is better to use std::vector<std::string> for array of strings
You have a two dimensional array of char
char arr[number][7];
And then trying to assign a string (char* or const char*) to them which will not work. What you can do here is assign a character, for example:
arr[0][1] = 'a';
If you can I would recommend using std::vector and std::string it would make things much clearer. In your case you could do
cin>>arr[i];
But I would not recommend it as you could only store up to 6 character char* strings (plus the null terminator). You can also have an array of char*
char* arr[number];
then dynamically allocate memory to store the strings.
Using std::vector and std::string will usually save you headaches once you understand them. Since you are brand new to C++, it might be useful to understand what is going on with two-dimensional arrays anyhow.
When you say
char array[N][M];
With N and M being constants, not variables, you are telling the compiler to allocate N*M items of type char. There will be a block of memory dedicated to that array of size N*M*sizeof(char). (You can declare an array of anything, not just char. Since sizeof(char) is 1, the memory will be N*M bytes long.) If you looked at raw memory, the first byte in the memory would be where array[0][0] is. The second byte would be where array[0][1] is, an so on, for M bytes. Then you would see array[1][0]. This is called row-major order.
As #jbat100 mentioned, when you say array[i][j] you are referring to a single character. When you say array[i], you are referring to the address of row i in the array. There is no pointer actually stored in memory, but when you say array[i] the compiler knows that you mean that you want the address of row i in the array:
char* row_i = array[i];
Now if i>0, then row_i points to somewhere in the middle of that block of memory dedicated to the array. This would do the same thing:
char* row_i = &array[i][0];
If you have a string, "orange" and you know that the length of it is less than M, you can store it in a given row in the array, like this:
strcpy(array[i], "orange"); // or
array[i][0] = 'o'; array[i][1] = 'a'; ... array[i][6] = 0;
Or you could have said row_i instead of array[i]. This copies 7 bytes into the array in the location of row_i. The strcpy() also copies an extra byte which is a 0, and this is the convention for terminating a character string in C and C++. So the 7 bytes are six bytes, 'o', 'r', 'a', 'n', 'g', and 'e', plus a 0 byte. Now strcmp(row_i, "orange") == 0.
Beware that if your string is longer than M, the strcpy and the simple char assignments will not (probably) produce a compile error, but you will end up copying part of your string into the next row.
Read about pointers and arrays in a good C/C++ book.

list of char* to vector of strings

it looks like when I cout *cp, it only outputs the first letter of the string and after I put them in vector, my output is blank. what am I doing wrong?
//write a program to assign the elements from a list of char* pointers to c-style character strings to a vector of strings
#include <iostream>
#include <cstring>
#include <vector>
#include <list>
#include <string>
using namespace std;
int main ()
{
list<const char*> clist;
cout<<"please enter a string"<<endl;
for(string s; getline(cin,s); )
{
const char* cp=s.c_str();
clist.push_back(cp);
cout<<*cp;
}
cout<<*clist.begin();
vector<string> svec;
svec.assign(clist.begin(),clist.end());
for(vector<string>::iterator iter=svec.begin(); iter!=svec.end(); ++iter)
cout<<*iter<<endl;
return 0;
}
This will print the whole string:
cout << cp; // You're providing cout a const char *
This will only print one character:
cout << *cp; // You're providing cout a char
As to what's wrong with your vector, you're only storing pointers to strings, not strings themselves. The memory for the string has gone out of scope. As others have said, use std::string instead of raw const char *.
cout *cp, it only outputs the first letter of the string
Well, *cp is a character (the one found at the location to which the pointer cp pointers). So, yea, it will.
after I put them in vector, my output is blank
It's unfortunate that your program did not crash outright, as the pointers in your list become dangling pointers almost as soon as you store them.
Store std::strings from the very start.
cout<<*cp;
will output a single character because it points to a const char *
You need to do:
cout<<cp;
This will output the entire string pointed by cp.
You have a couple big problems here. First of all,
const char* cp=s.c_str();
returns a pointer to an internal member string within std::string. When you change the string, the value referenced by the returned pointer to c_str may be changed (may even be in a new location). So, the values in your list are not valid. Make sure you don't use c_str and try to make use of the result after the original string has been changed (unless you copy the c_str result into a new char array.
Also,
cout<<*cp;
only prints our your first element. Get rid of the * to print the whole c-string at that list element.
it looks like when I cout *cp, it only outputs the first letter of the string
*cp is the first letter of the string. cout << cp will print the whole string.
after I put them in vector, my output is blank.
Your list contains pointers to the contents of s, which is only valid within the body of the loop. Once the string goes out of scope, the pointer is "dangling" - pointing to deallocated memory. Trying to use the pointer will give undefined behaviour.
You'll need to keep hold of a copy of the string itself, either by making clist a list<string>, or by keeping the strings in another container, and storing pointers to the data in that container in clist.
Alternatively, you could use string literals rather than reading strings from cin. String literals live as long as the program, so there are no issues with dangling pointers.
(That's assuming that the comment in the first line of your code is a specification that you can't change. Otherwise, I'd get rid of clist completely, and push each string onto the back of svec as I read it. It's rarely a good idea to use pointers for anything.)

Reversing a string/sequence of characters using only pointers

I'm working on an assignment that requires myself to reverse a sequence of characters, which can be of any given type, using a pointer to the "front" of the sequence and a pointer to the "end" of the sequence.
In my current build, I begin by first attempting to switch the "front" and "end" characters. However, I receive an "access violation" during runtime.
My code at the moment:
#include <cstdlib>
#include <string>
#include <iostream>
using namespace std;
class StrReverse
{
public:
StrReverse(); //default constructor
void revStr(); //reverses a given c-string
private:
typedef char* CharPtr;
CharPtr front;
CharPtr end;
CharPtr cStr;
};
int main()
{
StrReverse temp = StrReverse();
temp.revStr();
system("pause");
return 0;
}
//default constructor
StrReverse::StrReverse()
{
cStr = "aDb3EfgZ";
front = new char;
end = new char;
}
//reverses a given string
void StrReverse::revStr()
{
for(int i = 0;i < 4;i++)
{
front = (cStr + i);
end = (cStr + (7 - i));
*front = *end;
}
}
The key restriction with this problem is that the reversal must be done using pointers. I realize that simply reversing a string is trivial, but this restriction has me scratching my head. Any constructive comments would be greatly appreciated!
You assign the string literal "aDb3EfgZ" to cStr, and string literals can't be modified. Your compiler most likely stores the string literal in read only memory, and when you try to write to *front you get an access violation because of that.
To get a modifiable string, make a copy of the literal. For example:
const char *cLit = "aDb3EfgZ";
cStr = new char[strlen(cLit)+1];
strcpy(cStr, cLit);
For further detail see for example this question and the ones mentioned there in the "Linked" section.
There are several problems with your code. For starters, why the class;
this is something I'd expect to be done with a simple function:
void reverse( char* begin, char* end );
And you don't need an index, since you've got the pointers already; you
can just increment and decrement the pointers.
Also, why do you allocate memory in your constructor. Memory that you
never use (or free).
Finally, you don't really inverse anything in your loop. You need to
swap the characters, not just copy the one at the end into the one at
the beginning.
And as for the access violation: a string literal is a constant. You
can't modify it. If you want to do the reverse in place, you'll need to
copy the string somewhere else (or use it to initialize an array).
Your constructor is gonna leak memory because you loose the pointers you allocate the front and end, those allocations aren't even needed. As for your problem, you can loop though the string to find the end using while(*endptr) endptr++;, from there the size of the string is endptr - startptr; which you use to allocate a temp buffer so you can do while(startptr != endptr) *tempbuf++ = *endptr--; then free the old string and set the temp buffer as the new string
The basic technique for an in-place reversal:
get a pointer (call it 'left') to the first character in the string.
get a pointer (call it 'right') to the last character in the string (not counting the trailing NUL character)
while the left pointer is less than the right pointer
swap the characters located by each pointer
increment the left pointer
decrement the right pointer
That's about all there is to it. Production of a reversed copy of the string requires a bit more work.