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.
Related
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.
I am learning pointers and i tried this following program
#include <iostream>
#include <cstdlib>
#include <cstdio>
using namespace std;
char* getword()
{
char*temp=(char*)malloc(sizeof(char)*10);
cin>>temp;
return temp;
}
int main()
{
char *a;
a=getword();
cout<<a;
return 0;
}
To my level of understanding, a is a pointer to a character, and in the function getword() I returned temp which I think the base &temp[0]. I thought that the output would be the first character of the string I enter, but I got the entire string in stdout. How does this work?
In the tradition of C, a char* represents a string. Indeed, any string literal in your program (e.g. "hello") will have a type of const char *.
Thus, cout::operator<<( const char * ) is implemented as a string-output. It will output characters beginning at the address it is given, until it encounters the string terminator (otherwise known as null-terminator, or '\0').
If you want to output a single character, you need to dereference the pointer into a char type. You can choose one of the following syntaxes:
cout << *a; // Dereference the pointer
cout << a[0]; // Use array index of zero to return the value at that address
It should be noted that the code you provided isn't very C++ish. For starters, we generally don't use malloc in C++. You then leak the memory by not calling free later. The memory is uninitialised and relies on cin succeeding (which might not be the case). Also, you can only handle input strings of up to 9 characters before you will get undefined behaviour.
Perhaps you should learn about the <string> library and start using it.
It's true that char* "points to a character". But, by convention, and because with pointers there is no other way to do so, we also use it to "point to more than one character".
Since use of char* almost always means you're using a pointer to a C-style string, the C++ streams library makes this assumption for you, printing the char that your pointer points to … and the next … and the next … and the next until NULL is found. That's just the way it's been designed to work.
You can print just that character if you like by dereferencing the pointer to obtain an actual char.
std::cout is an overloaded operator and when it receives a char * as an operand then it treats it as a pointer to c style string and it will print the entire string.
If you want to print the first character of the string then use
cout << *a;
or
cout << a[0];
In your code, std::cout is an ostream and providing a char* variable as input to operator<< invokes a particular operator function overload to write characters to the ostream.
std::ostream also has a operator overload for writing a single character to itself.
I'm assuming you now know how to dereference a char* variable, but you should be using std::string instead of an unsafe char* type.
Here is the correct code
#include <stdio.h>
#include <stdlib.h>
char* getword()
{
char*temp=(char*)malloc(sizeof(char)*10);
scanf("%s",temp);
return temp;
}
int main()
{
char *a;
a = getword();
int currChar = 1;
printf("%c",*(a + currChar)); //increment currChar to get next character
return 0;
}
I'm pretty new to C++ and I'm need to create MyString class, and its method to create new MyString object from another's substring, but chosen substring changes while class is being created and when I print it with my method.
Here is my code:
#include <iostream>
#include <cstring>
using namespace std;
class MyString {
public:
char* str;
MyString(char* str2create){
str = str2create;
}
MyString Substr(int index2start, int length) {
char substr[length];
int i = 0;
while(i < length) {
substr[i] = str[index2start + i];
i++;
}
cout<<substr<<endl; // prints normal string
return MyString(substr);
}
void Print() {
cout<<str<<endl;
}
};
int main() {
char str[] = {"hi, I'm a string"};
MyString myStr = MyString(str);
myStr.Print();
MyString myStr1 = myStr.Substr(10, 7);
cout<<myStr1.str<<endl;
cout<<"here is the substring I've done:"<<endl;
myStr1.Print();
return 0;
}
And here is the output:
hi, I'm a string
string
stri
here is the substring I've done:
♦
Have to walk this through to explain what's going wrong properly so bear with me.
int main() {
char str[] = {"hi, I'm a string"};
Allocated a temporary array of 17 characters (16 letters plus a the terminating null), placed the characters "hi, I'm a string" in it, and ended it off with a null. Temporary means what it sound like. When the function ends, str is gone. Anything pointing at str is now pointing at garbage. It may shamble on for a while and give some semblance of life before it is reused and overwritten, but really it's a zombie and can only be trusted to kill your program and eat its brains.
MyString myStr = MyString(str);
Creates myStr, another temporary variable. Called the constructor with the array of characters. So let's take a look at the constructor:
MyString(char* str2create){
str = str2create;
}
Take a pointer to a character, in this case it will have a pointer to the first element of main's str. This pointer will be assigned to MyString's str. There is no copying of the "hi, I'm a string". Both mains's str and MyString's strpoint to the same place in memory. This is a dangerous condition because alterations to one will affect the other. If one str goes away, so goes the other. If one str is overwritten, so too is the other.
What the constructor should do is:
MyString(char* str2create){
size_t len = strlen(str2create); //
str = new char[len+1]; // create appropriately sized buffer to hold string
// +1 to hold the null
strcpy(str, str2create); // copy source string to MyString
}
A few caveats: This is really really easy to break. Pass in a str2create that never ends, for example, and the strlen will go spinning off into unassigned memory and the results will be unpredictable.
For now we'll assume no one is being particularly malicious and will only enter good values, but this has been shown to be really bad assumption in the real world.
This also forces a requirement for a destructor to release the memory used by str
virtual ~MyString(){
delete[] str;
}
It also adds a requirement for copy and move constructors and copy and move assignment operators to avoid violating the Rule of Three/Five.
Back to OP's Code...
str and myStr point at the same place in memory, but this isn't bad yet. Because this program is a trivial one, it never becomes a problem. myStr and str both expire at the same point and neither are modified again.
myStr.Print();
Will print correctly because nothing has changed in str or myStr.
MyString myStr1 = myStr.Substr(10, 7);
Requires us to look at MyString::Substr to see what happens.
MyString Substr(int index2start, int length) {
char substr[length];
Creates a temporary character array of size length. First off, this is non-standard C++. It won't compile under a lot of compilers, do just don't do this in the first place. Second, it's temporary. When the function ends, this value is garbage. Don't take any pointers to substr because it won't be around long enough to use them. Third, no space was reserved for the terminating null. This string will be a buffer overrun waiting to happen.
int i = 0;
while(i < length) {
substr[i] = str[index2start + i];
i++;
}
OK that's pretty good. Copy from source to destination. What it is missing is the null termination so users of the char array knows when it ends.
cout<<substr<<endl; // prints normal string
And that buffer overrun waiting to happen? Just happened. Whups. You got unlucky because it looks like it worked rather than crashing and letting you know that it didn't. Must have been a null in memory at exactly the right place.
return MyString(substr);
And this created a new MyString that points to substr. Right before substr hit the end of the function and died. This new MyString points to garbage almost instantly.
}
What Substr should do:
MyString Substr(int index2start, int length)
{
std::unique_ptr<char[]> substr(new char[length + 1]);
// unique_ptr is probably paranoid overkill, but if something does go
// wrong, the array's destruction is virtually guaranteed
int i = 0;
while (i < length)
{
substr[i] = str[index2start + i];
i++;
}
substr[length] = '\0';// null terminate
cout<<substr.get()<<endl; // get() gets the array out of the unique_ptr
return MyString(substr.get()); // google "copy elision" for more information
// on this line.
}
Back in OP's code, with the return to the main function that which was substr starts to be reused and overwritten.
cout<<myStr1.str<<endl;
Prints myStr1.str and already we can see some of it has been reused and destroyed.
cout<<"here is the substring I've done:"<<endl;
myStr1.Print();
More death, more destruction, less string.
Things to not do in the future:
Sharing pointers where data should have been copied.
Pointers to temporary data.
Not null terminating strings.
Your function Substr returns the address of a local variable substr indirectly by storing a pointer to it in the return value MyString object. It's invalid to dereference a pointer to a local variable once it has gone out of scope.
I suggest you decide whether your class wraps an external string, or owns its own string data, in which case you will need to copy the input string to a member buffer.
I have a confusion while dealing with char pointers. Please have a look at following code:
class Person
{
char* pname;
public:
Person(char* name)
{
//I want to initialize 'pname' with the person's name. So, I am trying to
//achieve the same with different scenario's
//Case I:
strcpy(pname, name); // As expected, system crash.
//Case II:
// suppose the input is "ABCD", so trying to create 4+1 char space
// 1st 4 for holding ABCD and 1 for '\0'.
pname = (char*) malloc(sizeof(char) * (strlen(name)+1) );
strcpy(pname, name);
// Case III:
pname = (char*) malloc(sizeof(char));
strcpy(pname, name);
}
void display()
{
cout<<pname<<endl;
}
};
void main()
{
Person obj("ABCD");
obj.display();
}
For Case I:
As expected, system crash.
Output for Case II:
ABCD
Output for Case III:
ABCD
So, I am not sure why Case II & III are producing the same output !!!!.....
How I should initialize a char pointer in a class?
The third case invokes Undefined Behavior and so anything might happen in that case.
You are writing beyond the bounds of allocated memory in this case which may or maynot crash but is a UB.
How to do this the right way in C++?
By not using char * at all!
Just simply use std::string.
Note that std::string provides you with c_str() function which gets you the underlying character string. Unless, You are bothered about passing ownership of a char * to a c-style api you should always use std::string in c++.
The third option is also wrong as you haven't allocated enough memory for it. You're trying to copy a string of size 5 to a buffer of size 1, which means the data after pname[1] are incorrectly overwritten and gone..
If you're lucky, you may see a runtime error such as memory access violation, or you won't see anything but the data behind it is corrupted, e.g., your bank account, and you never know about it until..
The correct way to go is to always allocate enough memory to copy to. A better way in C++ is to use std::string, as Als points out, because it'll free you from manual management of memory (allocation, growing, deallocation, etc).
E.g.,
class Person
{
std::string pname;
public:
Person(char* name)
{
pname = name;
}
void display()
{
cout << pname << endl;
}
};
void main()
{
Person obj("ABCD");
obj.display();
}
You have to allocate memory for your member variable pname, however, I don't know why you want to use a char* when you can just use a string:
std::string pname;
//...
pname = std::string(name);
If there is a good reason why you must use a char*, then do something of the sort:
// initialize the pname
pname = new char[strlen(name)];
// copy the pname
strcpy(pname, name);
The reason why you don't need to allocate an extra space at the end of the string for null-termination is because using the double quotes "blah" automatically produces a null-terminated string.
If you are into C++ business, then it's time to dump char pointers on behalf of STL string:
#include <string>
class Person
{
std::string the_name;
public:
Person(std::string name) : the_name(name)
{ ...
Also cout is used the same.
In your Case III, you do pname = (char*) malloc(sizeof(char));, which allocates enough memory for a single char. However, strcpy has no way of knowing that, and writes over whatever memory comes directly after that byte, until it has finished copying over all of the char* you passed into the function. This is known as a buffer overflow, and while this might immediately work, it could possibly break something down the road. If you are looking to copy only a subsection of the char*, you could look into strncpy, which copies up to some length (API reference here). If you use that, be sure to add the null-terminating character yourself, as strncpy will not include it if you copy only part of the string.
That pname = (char*) malloc(sizeof(char)); works is coincidental, the call to strcpy writes into memory that hasn't been allocated, so it could crash your program at any time.
A simpler way to initialize your buffer would be:
pname = strdup(name);
or
pname = strndup(name, strlen(name));
See http://linux.die.net/man/3/strdup.
Also, you must think about freeing the memory allocated by calling free(pname); in the class destructor.
All in all, all of this can be avoided by the use of the C++ std::string class, as mentioned by everyone.
Correct is case II!
Yes, case I is wrong, it will crash since you are copying data to a non initialized pointer.
Case III is also wrong, but it works now because your test string is small! If you try with a bigger string it will corrupt memory since you are copying a big string to a small allocated space.
In some systems malloc works with clusters so it works by allocating chuncks of memory instead of allocating byte-by-byte. This means that when you used malloc to alocate a single byte (like you did in case III), it allocates some more up to reach the minimum block of memory it can handle, that's why you could move more then 1 byte to it without crashing the system.
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.