a simple c++ program crashes? - c++

Write a program that asks the user to enter his or her first name and then last
name, and that then constructs, stores, and displays a third string, consisting of the
user’s last name followed by a comma, a space, and first name.Use char arrays and
functions from the cstring header file.A sample run could look like this:
Enter your first name: Flip
Enter your last name: Fleming
Here’s the information in a single string: Fleming, Flip
int main()
{
char * fName,*lName,*fullName;
fName = new char;
cin.getline(fName,100);
lName=new char;
cin.getline(lName,100);
fullName=new char[strlen(lName)+strlen(fName)+3];
strncpy(fullName,lName,strlen(lName));
fullName[strlen(lName)]=',';
fullName[strlen(lName)+1]=' ';
char* dummy=(char*)fullName[strlen(lName)+2];//making a pointer to the char after the ' ' char to start copying the first name
strncpy(dummy,fName,strlen(fName));
dummy[strlen(fName)+strlen(lName)+2]='\0';
cout<<endl<<endl<<dummy<<endl;
delete fullName;
delete lName;
delete fName;
return 0;
}
why it crashes when i point to a char in the middle of the array and start copying ???

fName = new char;
allocates a single char.
cin.getline(fName,100);
goes way beyond that.
Use std::string instead. You'll see that writing C++ code in C++ instead of C makes life a lot easier.

The type of fullName[strlen(lName)+2] is char, to get the pointer do:
char* dummy=fullName + strlen(lName)+2;

Related

In C++ while using cin.get(), how can I not limit the number of characters a user can enter?

Im trying to get a users input using cin.get() but I dont want to limit the amount of characters that they can enter. How can I do this?
EDIT: I guess a better way to phrase this would be: How can I dynamicaly change the character array to fit the length of the users input?
This is a strange requirement for a C++ program. You can of course go the C way and simply keep on getting more memory whenever your input outgrows the currently available memory. It goes something like this (warning: code fragments ahead):
while(cin.get(c)) {
if (cur_pos == cur_len) {
cur_len = grow_charbuf(buffer, cur_len);
}
buffer[cur_pos++] = c;
}
Here, the grow function is where it gets ugly. It needs to allocate a larger piece of memory, copy the contents of the current buffer to the beginning of that, dealocate the memory occupied by the current buffer, and return the new size. For example, something along these lines:
char* new_charbuf(size_t len) {
return new char [len];
}
size_t grow_charbuf(char* buf, size_t cur_len) {
size_t new_len = cur_len * 2;
char* new_buf = new char [new_len];
// copy old buffer contents to new buffer
delete[] buf;
buf = new_buf;
return new_len;
}
And you can then use it as follows:
cur_len = 1000; // or whatever
char* buffer = new_charbur(cur_len);
// write into the buffer, calling grow_charbuf() when necessary
// and don't forget to free the memory once you are done...
// or don't free it, if the program eventually exits anyway
This is terrible code. It might work, but you should never ever do this in C++ if you can avoid it. Apart from this, I have avoided handling any error conditions or exceptions that this code might cause. It is meant just to illustrate the idea.
Managing your memory manually is a bad idea because it requires a lot of code and is not easy to get right. You can get away with less if your program has a known, limited life-span.
Don't use characters array at all. Use std::string or other standard containers.
And of cause learn to use streams.
Here an example. It reads as many characters as the user inputs until the user presses enter. As you cna see, there is no explicite buffer-size required:
/////TEST PUT ANYWHERE IN GLOBAL SCOPE
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
int test()
{
//SET BP HERE AND STEP THROUGH
string line;
getline(cin,line);
std::stringstream user_input( line );
while(!user_input.eof())
{
string word;
user_input >> word;
cout << word << endl;
}
return 0;
}
static int _test = test();
/////END TEST
You need a cin.getline(). In other words you need to have a specified size of char array and use it like so:
Using cin.get()
char str[100];
char sayHello[100];
cin.get(str, 100);
// make sure to add cin.ignore() or program will terminate right before next cin().
cin.ignore();
cout << str << endl;
cin.get(sayHello, 100);
cout << sayHello;
or for cin.getline()
char input[100];
cin.ignore(); // stops the sentence from truncating.
cin.getline(input,sizeof(input));
You could also use getline() for strings like so:
string name;
getline(cin, name);
The problem is that in c++ when receiving input your cin looks for the 0 aka the space in your sentence. It then ends thinking that was the end.

Passing control character to char array

This one
char *house2="JAM gain\r\n"
differs from this one:
string house, prefix="JAM ", suffix="\r\n";
cin>>house;
house = prefix + nickname + suffix;
char house2[100];
strncpy(house2, house.c_str(), sizeof(house));
return house2;
Even though I type "gain" on keyboard, I need to pass this char array with control-characters to api because without them it seems it's not working. what can I do to solve problem?
Ok real code:
string nickname, prefix="NICK ", suffix="\r\n";
cout<<"Choose nickname\n";
cin>>nickname;
nickname = prefix + nickname + suffix;
cout<<nickname;
char nick[100];
strncpy(nick, nickname.c_str(), sizeof(nickname));
return nick;
sizeof is not doing what you think. Instead of
strncpy(nick, nickname.c_str(), sizeof(nickname));
you want
strncpy(nick, nickname.c_str(), nickname.size());
But even then you open yourself up to buffer-overflow, so you really want
strncpy(nick, nickname.c_str(), sizeof(nick));
Next problem is that nick is local to your function so returning it is going to "cause bad things". You could make it static (and then run into complex problems with threads later...) or you could pass it in as an argument (which would then mean you couldn't use sizeof, for technical reasons). What you really need is something a lot simpler - just return the string, not the C string.
string getNick() {
string nickname, prefix="NICK ", suffix="\r\n";
cout<<"Choose nickname\n";
cin>>nickname;
nickname = prefix + nickname + suffix;
cout<<nickname;
return nickname;
}
And just to show that it really is doing what its supposed to be, here's a working online version. Here's its full code for posterity:
#include <iostream>
#include <string>
std::string getNick() {
std::string nickname, prefix="NICK ", suffix="\r\n";
std::cout<<"Choose nickname\n";
std::cin>>nickname;
nickname = prefix + nickname + suffix;
std::cout<<nickname;
return nickname;
}
int main() {
std::string nick = getNick();
std::cout<<"in main nick = '"<<nick<<"'"<<std::endl;
}
Input
gain
.
Output
Choose nickname
NICK gain
in main nick = 'NICK gain
'
Since you have an API that takes a C string, you'll need to check the details for that api for ownership of the C-string - there are two options.
The API takes ownership of the C string and will dealloc it later.
The API makes a copy of the C string, and you control its lifetime.
In the first case you need to do this: (I'm assuming a C api, which will eventually free the passed in pointer - if its a badly designed C++ API which will delete[] it, you need to replace the malloc with a new char[nick.size()]
string nick = getNick();
char * buffer = (char*)malloc(nick.size()+1);
memcpy(buffer, nick.c_str(), nick.size());
buffer[nick.size()]=0;
your_api(buffer);
In the second case you can simply do
your_api(getNick().c_str());
Your code should be
string house, prefix="JAM ", suffix="\r\n";
string nickname;
cin>>nickname;
house = prefix + nickname + suffix;
char house2[100];
strncpy(house2, house.c_str(), sizeof(house2));
//or strncpy(house2, house.c_str(), house.length());
return string(house2);
Do not return house2 as char* as the memory will be destroyed once the function exits.
PROBLEM SOLVED (why? :P )
string prawniczek=choosenick();
int TempNumOne=prawniczek.size();
char niczek[40];
for (int a=0;a<=TempNumOne;a++)
{
niczek[a]=prawniczek[a];
}
ok problem was solved by simple rewriting chars at index position one by one
it has to mean that
strncpy with nickname.c_str() works different.
anyway - i think that way is not elegant, even though it works
does anyone know how to do it in correct way?
UPDATE:
moreover:
when the loop is in main at translate to char array from choosenick() method it works perfectly, but when i do it inside method choosenick() and return translated loop result to main it doesn't work

Why does a C++ string need a \0?

I was hoping that I could get some further explanation. I was told that I need to explicitly add \0 to the end of a string. Apparently this is for the C++ string class and that it is actually an array of characters that seems to be parsed under the hood. I was told that we must use the \0 in order to tell where the end of the string is as seen below:
int main()
{
char str[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
cout << str << endl;
return 0;
}
However, if I have a user input their name, for example, I don't believe that C++ automatically uses the \0 to terminate the string. So the argument that the \0 must be there to know where the string ends makes no sense. Why cant we use the .length() function to account for the length of the string?
I wrote the following program to illustrate that the length of the input can be found from the .length() function.
int main()
{
string firstName;
cout << "Enter your first name: ";
cin >> firstName;
cout << "First Name = " << firstName << endl;
cout << "String Length = " << firstName.length() << endl;
return 0;
}
So, if the user inputs the name "Tom". Then the output would be the following:
First Name = Tom
String Length = 3
I brought this to my professor's attention and also this article http://www.cplusplus.com/reference/string/string/length/
and I was told that is why I am in college because it cannot be done this way. Can any one offer any insight, since I don't understand what I am missing?
The "C string" was adopted into C++ from the C language. The C language did not have a string type. Strings in C were represented as an array of char, and the string was terminated with the NUL byte (\0). A plain string literal in C++ still has these semantics.
The C++ string type maintains the length within the object, as you say, so in a string, the NUL is not required. To get a "C string" from a string, you can use the c_str() method on the string. This is useful if you need to pass the contents of the C++ string to a function that only understands the NUL terminated variety.
std::string s("a string"); // s is initialized,
// the length is computed when \0 is encountered.
assert(s.size() == sizeof("a string")-1);
// sizeof string literal includes the \0
assert(s.c_str()[s.size()] == '\0');
// c_str() includes the \0
In your first program, you are initializing an array of char with an initializer list. The initialization is equivalent to the following:
char str[6] = "Hello";
This style of initializing an array of char is a special allowance that C++ provides since it is the syntax accepted by C.
In your second program, you are getting the name from the standard input. When C++ scans the input to populate the string argument, it essentially scans byte by byte until it encounters a separator (whitespace characters, by default). It may or may not insert a NUL byte at the end.
You're not missing anything per se. The null terminator is used on character arrays to indicate the end. However, the string class takes care of all of that for you. The length attribute is a perfectly acceptable way of doing it since you're using strings.
However, if you're using a character array, then yes, you would need to check if you're on the null terminator, as you may not know the length of your string.
The following will give you no issues.
int length = 2;
char str[] = "AB";
However, try the following, and you'll see some issues.
int length = 5;
char str[length + 1] = "ABCDE"; // +1 makes room for automatic \0
char str2[length + 1] = "ABC";
Try the second snipped using your for loop method knowing the length, and the first one will give you ABCDE, but the second one will give you "ABC" followed by one junk character. It's only one because you'll have [A][B][C][\0][JUNK] in your array. Make length larger and you'll see more junk.

Adding char to string in C++

I work with Eclipse and Arduino.
I want to add a char to a string. I tried to use append,insert ( but these can not be resolved)
I tried to use += but when i print the string it always have one char.Basically i deletes the string and writes only the new char i want to add in.
I tried also concat and it does the same thing.Also strcat gives me headache with the operands cause it needs a const char pointer and i want to add a char that changes.
while (theSettings.available()) {
character = theSettings.read();
if(character == '/') {
// Comment - ignore this line
while(character != '\n'){
character = theSettings.read();
}
} else if(isalnum(character)){ // Add a character to the description
Serial.println(character);
description +=character;
//description.concat(character);
Serial.println(description);
}
It sounds like what you want (for convenience) is the String object class available with the Arduino library.
http://arduino.cc/en/Reference/StringObject
If description is of the Ardunio-specific String type, you should be able to use the += operator to append.
You can do a very simple thing;
Serial.print(character);
Serial.print("");
Serial.println(description);
alternatively you can use "dtostrf" if you need to concatenate float and strings

How to get only first words from several C++ strings?

I have several C++ strings with some words. I need to get the first word from every string. Then I have to put all of them into a char array. How can I do it?
Here is one way of doing it...
// SO2913562.cpp
//
#include <iostream>
#include <sstream>
using namespace std;
void getHeadWords(const char *input[]
, unsigned numStrings
, char *outBuf
, unsigned outBufSize)
{
string outStr = "";
for(unsigned i = 0; i<numStrings; i++)
{
stringstream ss(stringstream::in|stringstream::out);
ss<<input[i];
string word;
ss>>word;
outStr += word;
if(i < numStrings-1)
outStr += " ";
}
if(outBufSize < outStr.size() + 1)//Accomodate the null terminator.
//strncpy omits the null terminator if outStr is of the exact same
//length as outBufSize
throw out_of_range("Output buffer too small");
strncpy(outBuf, outStr.c_str(), outBufSize);
}
int main ()
{
const char *lines[] = {
"first sentence"
, "second sentence"
, "third sentence"
};
char outBuf[1024];
getHeadWords(lines, _countof(lines), outBuf, sizeof(outBuf));
cout<<outBuf<<endl;
return 0;
}
But note the above code has marginal error checking and may have security flaws. And needless to say my C++ is a bit rusty. Cheers.
I'll assume it's homework, so here is a general description:
First, you need to allocate enough space in your char array. In homework, you are usually told the maximum size. That maximum has to be enough for all the first words.
Now, you need to have an index for the insertion point in that array. Start it at zero.
Now go over your strings in order. In each, move an index forward from 0 until you see a \0 or a space (or other delimiter. Insert the character at the insertion point in the result array and increase that index by 1.
If you have encountered a space or a \0, you've found your first word. If you were on the last string, insert a \0 at the insertion point and you're done. If not, insert a space and move to the next string.
what compiler are you using?
converting to a chararray is the first thing to look for.
after done that, you can easily step through your array (and look for spaces)
something like this:
while (oldarray[i++] != ' ')
yournewarray[j++];
i think you gotta figure out the rest yourself, since this looks like some homework for school :)
Assuming this is homework, and that when you say "strings" you mean simple null-delimited arrays of char (and not std::string):
define your strings
define your resulting char array
for each string
find the offset of the first char that is not in the first word
append that many bytes of the string to the result array
If this is not homework, give us a little code to start with and we'll fill in the blanks.