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.
Related
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.
I have a function f() which receives a char* p and gives a const char* to it.
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
In the main() below I expect to get q = "def".
int main(){
char *q = "abc";
f(q);
cout << q << endl;
}
By running this I get segmentation fault and as I am new in C++ I don't understand why.
I also get a segmentation fault when I do not initialize q thus:
int main(){
char *q;
f(q);
cout << q << endl;
}
Knowing that the function's parameter and the way it's called must not change. Is there any work around that I can do inside the function? Any suggestions?
Thanks for your help.
You are trying to change a string literal. Any attemp to change a string literal results in undefined behaviour of the program.
Take into account that string literals have types of constant character arrays. So it would be more correct to write
const char *q = "abc";
From the C++ Standard (2.14.5 String literals)
8 Ordinary string literals and UTF-8 string literals are also referred
to as narrow string literals. A narrow string literal has type
“array of n const char”, where n is the size of the string as
defined below, and has static storage duration
You could write your program the following way
//...
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
//..
main(){
char q[] = "abc";
f(q);
cout << q << endl;
}
If you need to use a pointer then you could write
//...
void f(char *p) {
string s = "def";
strcpy(p, s.c_str());
}
//..
main(){
char *q = new char[4] { 'a', 'b', 'c', '\0' };
f(q);
cout << q << endl;
delete []q;
}
This is an issue that, in reality, should fail at compilation time but for really old legacy reasons they allow it.
"abc" is not not a mutable string and therefore it should be illegal to point a mutable pointer to it.
Really any legacy code that does this should be forced to be fixed, or have some pragma around it that lets it compile or some permissive flag set in the build.
But a long time ago in the old days of C there was no such thing as a const modifier, and literals were stored in char * parameters and programmers had to be careful what they did with them.
The latter construct, where q is not initialised at all is an error because now q could be pointing anywhere, and is unlikely to be pointing to a valid memory place to write the string. It is actually undefined behaviour, for obvious reason - who knows where q is pointing?
The normal construct for such a function like f is to request not only a pointer to a writable buffer but also a maximum available size (capacity). Usually this size includes the null-terminator, sometimes it might not, but either way the function f can then write into it without an issue. It will also often return a status, possibly the number of bytes it wanted to write. This is very common for a "C" interface. (And C interfaces are often used even in C++ for better portability / compatibility with other languages).
To make it work in this instance, you need at least 4 bytes in your buffer.
int main()
{
char q[4];
f(q);
std::cout << q << std::endl;
}
would work.
Inside the function f you can use std::string::copy to copy into the buffer. Let's modify f.
(We assume this is a prototype and in reality you have a meaningful name and it returns something more meaningful that you retrieve off somewhere).
size_t f( char * buf, size_t capacity )
{
std::string s = "def";
size_t copied = s.copy( buf, capacity-1 ); // leave a space for the null
buf[copied] = '\0'; // std::string::copy doesn't write this
return s.size() + 1; // the number of bytes you need
}
int main()
{
char q[3];
size_t needed = f( q, 3 );
std::cout << q << " - needed " << needed << " bytes " << std::endl;
}
Output should be:
de needed 4 bytes
In your question you suggested you can change your function but not the way it is called. Well in that case, you actually have only one real solution:
void f( const char * & p )
{
p = "def";
}
Now you can happily do
int main()
{
const char * q;
f( q );
std::cout << q << std::endl;
}
Note that in this solution I am actually moving your pointer to point to something else. This works because it is a static string. You cannot have a local std::string then point it to its c_str(). You can have a std::string whose lifetime remains beyond the scope of your q pointer e.g. stored in a collection somewhere.
Look at the warnings you get while compiling your code (and if you don’t get any, turn up the warning levels or get a better compiler).
You will notice that despite the type declaration, the value of q is not really mutable. The compiler was humoring you because not doing so would break a lot of legacy code.
You can't do that because you assigned a string literal to your char*. And this is memory you can't modify.
With your f, You should do
int main(){
char q[4 /*or more*/];
f(q);
std::cout << q << std::endl;
}
The problem is that you are trying to write on a read-only place in the process address space. As all the string literals are placed in read-only-data. char *q = "abc"; creates a pointer and points towards the read-only section where the string literal is placed. and when you copy using strcpy or memcpy or even try q[1] = 'x' it attempts to write on a space which is write protected.
This was the problem among many other solutions one can be
main(){
char *q = "abc"; \\ the strings are placed at a read-only portion
\\ in the process address space so you can not write that
q = new char[4]; \\ will make q point at space at heap which is writable
f(q);
cout << q << endl;
delete[] q;
}
the initialization of q is unnecessary here. after the second line q gets a space of 4 characters on the heap (3 for chars and one for null char). This would work but there are many other and better solutions to this problem which varies from situation to situation.
I am making a simple program that allows me to set the name of an object by sending an array of characters into a public member function which then changes a private variable called name. I then tell my class to spit the name variable out so I can see if it work correctly -- but my output comes out mostly garbled.
ie, I input
"Apple"
and the output becomes
"AAAAA╠╠╠╠Apple"
I notice that as I change the word, the number of repeating characters mimics the number of characters in the word - but I cannot seem to figure out where I messed up with my program. Here is my code:
*Note: code below now works as expected.
#include <iostream>
#include <cstring>
using namespace std;
class Item{
public:
~Item() { delete [] name; }
char *setName(char * inputName)
{
name = new char[strlen(inputName)+1];
int n = 0;
for(n = 0; n<strlen(inputName); n++)
name[n] = inputName[n];
name[n] = '\0';
return name;
}
private:
char *name;
};
int main()
{
char objectname[] = "Apple";
Item Apple;
cout << Apple.setName(objectname);
int input;
cin >> input; //pause program
}
As I said in my comment, you never allocate memory for name. When using name[n] you'll be dereference addresses that don't belong to you. This causes Undefined Behavior in your program, meaning anything can happen that doesn't conform to the logic of your program. It can even compile just fine, but you can't rely on that.
Anyway, you need to allocate memory for name. But for that you need to know the size of the memory to assign it to. We don't know the size of the memory (it can an arbitrary string that is sent to setName). Therefore name has to be a pointer:
char* name;
Then we can assign memory to it. BTW, char name[] is a zero-sized array, which is illegal in C++.
Inside setName, you need to get the size of the string that is sent to it. strlen is right for the job, but you also need to make room for the null-terminator ('\0'). It is the character that is appened to the end of every string, if you don't add it and try to print name later on, std::cout won't know where to stop printing each character (that's also Undefined Behavior).
Inside setName, this should be the assignment of the dynamic memory to name:
name = new char[strlen(inputName) + 1];
meaning: (number of characters in inputName + the null terminator). Note: strlen doesn't count the null-terminator.
Now, to set the null-terminator, you simply do this below the for() loop:
name[n] = '\0';
Moreover, when you are finished using the memory in name, you have to delete it. You do that using delete[]:
delete[] name;
The recommended alternative is to use std::string the standard C++ string class that manages memory by itself.
I'm reading the 3rd edition of The C++ Programming Language by Bjarne Stroustrup and attempting to complete all the exercises. I'm not sure how to approach exercise 13 from section 6.6, so I thought I'd turn to Stack Overflow for some insight. Here's the description of the problem:
Write a function cat() that takes two C-style string arguments and
returns a single string that is the concatenation of the arguments.
Use new to find store for the result.
Here's my code thus far, with question marks where I'm not sure what to do:
? cat(char first[], char second[])
{
char current = '';
int i = 0;
while (current != '\0')
{
current = first[i];
// somehow append current to whatever will eventually be returned
i++;
}
current = '';
i = 0;
while (current != '\0')
{
current = second[i];
// somehow append current to whatever will eventually be returned
i++;
}
return ?
}
int main(int argc, char* argv[])
{
char first[] = "Hello, ";
char second[] = "World!";
? = cat(first, second);
return 0;
}
And here are my questions:
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
Related to the previous question, what should I return from cat()? I assume it will need to be a pointer if I must use new. But a pointer to what?
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
How do I use new to find store? Am I expected to do something like std::string* result = new std::string; or should I be using new to create another C-style string somehow?
The latter; the method takes C-style strings and nothing in the text suggests that it should return anything else. The prototype of the function should thus be char* cat(char const*, char const*). Of course this is not how you’d normally write functions; manual memory management is completely taboo in modern C++ because it’s so error-prone.
Although the problem doesn't mention using delete to free memory, I know I should because I will have used new to allocate. Should I just delete at the end of main, right before returning?
In this exercise, yes. In the real world, no: like I said above, this is completely taboo. In reality you would return a std::string and not allocate memory using new. If you find yourself manually allocating memory (and assuming it’s for good reason), you’d put that memory not in a raw pointer but a smart pointer – std::unique_ptr or std::shared_ptr.
In a "real" program, yes, you would use std::string. It sounds like this example wants you to use a C string instead.
So maybe something like this:
char * cat(char first[], char second[])
{
char *result = new char[strlen(first) + strlen(second) + 1];
...
Q: How do you "append"?
A: Just write everything in "first" to "result".
As soon as you're done, then continue by writing everything in "second" to result (starting where you left off). When you're done, make sure to append '\0' at the end.
You are supposed to return a C style string, so you can't use std::string (or at least, that's not "in the spirit of the question"). Yes, you should use new to make a C-style string.
You should return the C-style string you generated... So, the pointer to the first character of your newly created string.
Correct, you should delete the result at the end. I expect it may be ignored, as in this particular case, it probably doesn't matter that much - but for completeness/correctness, you should.
Here's some old code I dug up from a project of mine a while back:
char* mergeChar(char* text1, char* text2){
//Find the length of the first text
int alen = 0;
while(text1[alen] != '\0')
alen++;
//Find the length of the second text
int blen = 0;
while(text2[blen] != '\0')
blen++;
//Copy the first text
char* newchar = new char[alen + blen + 1];
for(int a = 0; a < alen; a++){
newchar[a] = text1[a];
}
//Copy the second text
for(int b = 0; b < blen; b++)
newchar[alen + b] = text2[b];
//Null terminate!
newchar[alen + blen] = '\0';
return newchar;
}
Generally, in a 'real' program, you'll be expected to use std::string, though. Make sure you delete[] newchar later!
What the exercise means is to use new in order to allocate memory. "Find store" is phrased weirdly, but in fact that's what it does. You tell it how much store you need, it finds an available block of memory that you can use, and returns its address.
It doesn't look like the exercise wants you to use std::string. It sounds like you need to return a char*. So the function prototype should be:
char* cat(const char first[], const char second[]);
Note the const specifier. It's important so that you'll be able to pass string literals as arguments.
So without giving the code out straight away, what you need to do is determine how big the resulting char* string should be, allocate the required amount using new, copy the two source strings into the newly allocated space, and return it.
Note that you normally don't do this kind of memory management manually in C++ (you use std::string instead), but it's still important to know about it, which is why the reason for this exercise.
It seems like you need to use new to allocate memory for a string, and then return the pointer. Therefore the return type of cat would be `char*.
You could do do something like this:
int n = 0;
int k = 0;
//also can use strlen
while( first[n] != '\0' )
n ++ ;
while( second[k] != '\0' )
k ++ ;
//now, the allocation
char* joint = new char[n+k+1]; //+1 for a '\0'
//and for example memcpy for joining
memcpy(joint, first, n );
memcpy(joint+n, second, k+1); //also copying the null
return joint;
It is telling you to do this the C way pretty much:
#include <cstring>
char *cat (const char *s1, const char *s2)
{
// Learn to explore your library a bit, and
// you'll see that there is no need for a loop
// to determine the lengths. Anything C string
// related is in <cstring>.
//
size_t len_s1 = std::strlen(s1);
size_t len_s2 = std::strlen(s2);
char *dst;
// You have the lengths.
// Now use `new` to allocate storage for dst.
/*
* There's a faster way to copy C strings
* than looping, especially when you
* know the lengths...
*
* Use a reference to determine what functions
* in <cstring> COPY values.
* Add code before the return statement to
* do this, and you will have your answer.
*
* Note: remember that C strings are zero
* terminated!
*/
return dst;
}
Don't forget to use the correct operator when you go to free the memory allocated. Otherwise you'll have a memory leak.
Happy coding! :-)
I am currently working on writing strstr from scratch. In my code, I am indexing a string and I eventually need to save a particular point on the string using another pointer. Here is the section of the code that I am struggling with:
char *save_str;
for(int i=0;i<length_str1; i++)
{
if(str1[i]==str2[0])
{
*save_str=str[i];
However, it is telling me that I cannot do this. How can I have a pointer point to a particular character in an index?
You can choose from these two ways:
save_str = &str[i];
or
save_str = str+i;
Quick Practical Answer
save_str = &str[i];
Extended Descriptive Boring Answer
There is a feature in "pure c" and "c++" about arrays and pointers.
When a programmer wants the address of the full array, or the first item, the "&" operator is not required, even considered as an error or warning by some compilers.
char *myptr = NULL;
char myarray[512];
strcpy(myarray, "Hello World");
// this is the same:
myptr = myarray;
// this is the same:
myptr = &myarray[0];
When a programmer wants the address of a particular item, then the "&" operator is required:
save_str = &str[i];
I read somewhere, that, these feature was added, in purpouse.
Many developer avoid this, and use pointer arithmetics, instead:
...
char *save_str;
...
// "&" not required
char *auxptr = str1;
for(int i=0; i < length_str1; i++)
{
// compare contents of pointer, not pointer, itself
if(*auxptr == str2[0])
{
*save_str = *auxptr;
}
// move pointer to next consecutive location
auxptr++;
}
...
Personally, I wish, "&" should be use always, and avoid confusion.
Cheers.