I try to verify if user did not input anything , this way
bool null_input = false;
int i = 0;
while (null_input == false) {
char *name = new char[255];
std::cout<<"Name :";
std::cin>>name;
if (name == "") {
null_input = true;
break;
}
else star[i++].name = name;
}
Anyway if i press ENTER without to input anything , cin still waits a valid input. Question is how to correctly to verify is nothing was introduced ?
The C++ == operator is going to actually compare the pointers. You want to use a string, not a char* (or use strcmp in C style).
For example:
char*a = "abc"
char*b = "abc"
a == b
returns false.
The statement:
std::cin >> name
Will skip every blank character before starting the real reading. The following characters are considered blan (whitespace, tab, CR).
So, it will wait until somthing different from a blak is typed before starting to read in `name'.
Note that this code is unsafe if the typed string is longer thant the buffer size (255).
As far as I understood you are not allowed to use c++ string, so hope that this c-style code could work for you
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
const int name_size = 255;
char *name = new char[name_size];
while (true) {
cout << "Name :";
cin.getline(name, name_size);
if (strlen(name) != 0) break;
cout << "not a valid name...";
}
cout << "got the name " << name << " -- it is OK!\n";
delete [] name;
return 0;
}
Hope it helps, have a fun with char * ! ))
Aside from the non-C++-ness of your code, the exact problem is that name is a pointer to chars, and "" is an array of chars. The code name == "" returns false, since name does not point to the first char in the array. Instead, you'll want to check if already allocated array is empty, by checking if the NULL terminator is the first character. if (name[0] == '\0')
Now for the C++ ness: don't use char*, use std::string. Also, your code to keep prompting if you got invalid data is backwards.
You should also remember that anything which is created by "new" must be released. There is a critical memory leak in your algorithm. Heap allocation isnt a good way in this case.
The easiest solution is to use std::string. It is more safe ( there is no memory leak and you can put string longer than 255 signs). There is also I++ in [i++] make sure that "i" will not be higher than a array size ( i guess it is a array). There is a std::vector which can help you.
Related
This is an oddly specific problem but I need help because I am very confused. I am trying to use pointers to ask a user to input a string and the output will print the reverse. So far I have used a reverse function and applied the pointers. Here's what the code looks like right now:
#include <iostream>
using namespace std;
void reverse(char name[])
{
char *p;
p = name;
while (*p != '\0')
{
++p;
}
while (*p >= 0)
{
cout << *p;
--p;
}
}
int main()
{
char name[100];
cout << "Please enter a string: ";
cin.getline(name, sizeof(name));
cout << "The reverse of the string is: ";
reverse(name);
return 0;
}
When I run the program, it works but there is one problem. For example the inputted string is Stack Overflow, this is the result:
Please enter a string: Stack Overflow
The reverse of the string is: wolfrevO kcatS ►☺ ◄ a
As you can see there are these symbols that show up in the final output. I have tried locating where it comes from and I think it is because of the pointers because when I used an array for the function, it properly printed the reversed string without the symbols. I am asking if there is a way for me to remove these symbols while still using pointers? I have tried multiple variations on making the function with the pointers but the symbols still print at the end.
That garbarge happens because you don't have null terminating character at the beginning of the string, thus you don't terminate when going backwards. I modified your code to keep sentinel zero character at 0-th position, and now your code works without bugs.
Also condition while (*p >= 0) should be replaced with while (*p).
Try it online!
#include <iostream>
using namespace std;
void reverse(char name[])
{
char *p;
p = name;
while (*p != '\0')
{
++p;
}
--p;
while (*p)
{
cout << *p;
--p;
}
}
int main()
{
char name[100];
name[0] = 0;
cout << "Please enter a string: ";
cin.getline(name + 1, sizeof(name) - 1);
cout << "The reverse of the string is: ";
reverse(name + 1);
return 0;
}
Input:
Please enter a string: Stack Overflow
Output:
The reverse of the string is: wolfrevO kcatS
When you use
while (*p >= 0)
{
cout << *p;
--p;
}
you seem to assume that the space just before the beginning of the array is occupied by something negative; this is not a safe assumption, and the loop can iterate past that point, printing whatever binary junk happens to be in that region of memory. I say it can, because dereferencing a pointer into unallocated space like that is undefined behavior. It can do anything; it can terminate the loop so that the program appears to work correctly, it can print gibberish, it can crash you computer.
If you want to stop at the beginning of the given string, look for the beginning of the given string:
do
{
--p;
cout << *p;
}
while (p != name);
You're reading 100 characters into the string, which means there's a chance some trash input buffer values will be read too. This is where the symbols come from. Since you're using char arrays, maybe instead of getline use something like this:
char c = getchar();
int i = 0;
while(c != '\n'){
name[i] = c;
c= getchar();
i++;
}
name[i++] = '\0'
This way you'll only read what you need to read, and will have the terminating character '\0' at the end of the string. Bear in mind there's probably a cleaner solution using getline tho. Either way, the problem is that you're reading more values then you want to read into the char array, and since you're directly accessing memory you need to figure out a way to add a '\0' after the desired string, so the method knows when to stop - I'm guessing char arrays are implemented in such a way to secure this always happens, hence the reason it works with char arrays but not with pointers.
I have a function called SearchArray() which calls another function called SearchRecords(char StudentNo[]) to check the database array of gRecs for a match in student numbers.
When i run the debugger the value of StudentNo is being shown as StudentNo = 0x22fde0 "12345678" if StudentNum = "12345678".
What are these additional characters?
SearchArray() function
void SearchArray(){
char studentNum[8];
cout << "Enter student number: ";
cin >> studentNum;
char i = SearchRecords(studentNum);
if (gRecs[i].studentNumber != studentNum){
cout << "Record not found" << endl;
}
else {
PrintRecord(i);
}
}
SearchRecords() function
int SearchRecords(char StudentNo[])
{
for (int i = 0; i < gNumRecs; i++){
if(gRecs[i].studentNumber == StudentNo)
{
return i;
}
}
return -1; //not found
}
Do you mean the "0x22fde0"? Those aren't in your character array, your character array only contains the part in quotes ("12345678"). The hexadecimal number 0x22fde0 is the address of the first character. In C/C++, any array is really just a pointer to the first element: the value of the variable is the address of the first element. So the debugger is showing you that address value. But it also knows that character arrays usually store strings, so it is also helpfully showing you the contents of that array as a string.
As this comment notes, you're comparing pointers not strings. You'll save yourself many headaches by changing your studentNumber type to std::string. This will allow you to use comparison operators(==,!=,<,<=,>,>=) with either a std::string or a raw string(char*) on the right side. I highly recommend reading up on strings at tutorialspoint.com and cplusplus.com.
When posting in the future, please post any relevant custom data structures(such as the layout of your gRecs element type), it helps us solve the problem faster.
The problem is that I would like to allocate memory dynamically according to the size of user's input.Please note that the user does not specify the size of input. We have to calculate how long it was, and then only allocate the exact amount of memory for it.What I'm looking for is something like this:
char* input_str = NULL; // No initial size whatsoever
cout<<"\nEnter the string: ";
//Determine how long the string entered was, and allocate memory for it
//make input_str point to it.
May be this can help us write our version of std::string ?
Just use a std::string, which does all of this for you:
std::cout << "\nEnter the string: ";
std::string input;
// To get a word:
std::cin >> input;
// To get a line of input:
std::getline(std::cin, input);
You won't need to worry about memory allocation at all.
Internally, these functions will call std::cin.rdbuf() to get access to the underlying stream buffer and read character by character until the stopping condition is met. As it does this, it grows some internal storage than it (de)allocates with new[] and delete[].
An alternative simple (but limited and potentially dangerous) approach you might use, is to allocate a buffer that is as large as you're ever going to need (something like new char[100] and read the input into it (with something like std::cin.read or std::cin.getline, etc.). Then you can determine how many characters were inserted into the buffer, allocate some storage of the correct size, transfer your input into this storage, and then deallocate the old buffer. With this approach, you have to be extra careful to avoid buffer overflows which may introduce security vulnerabilities to your program, and you are of course limited to a particular maximum input size.
As I understand the question, in particular the “May be this can help us write our version of std::string ”, it's about
doing what std::getline from the <string> header does, to see what that involves.
That's already discussed in a good way by Bjarne Stroustrup in his paper “Learning Standard C++ as a New Language”, except that Bjarne discusses input via the >> operator, which only inputs a single whitespace-delimited word.
Bjarne starts with pseudo-code for a hypothetical student's exercise:
write a prompt "Please enter your first name"
read the name
write out "Hello <name>"
He then presents one possible C++ solution:
#include<iostream> // get standard I/O facilities
#include<string> // get standard string facilities
int main()
{
using namespace std; // gain access to standard library
cout << "Please enter your first name:\n";
string name;
cin >> name;
cout << "Hello " << name << '\n';
}
And after some discussion he presents a C style solution, a DIY C style program to do just about the same as the C++ style solution:
#include<stdio.h>
#include<ctype.h>
#include<stdlib.h>
void quit() // write error message and quit
{
fprintf(stderr," memory exhausted\n") ;
exit(1) ;
}
int main()
{
int max = 20;
char* name = (char*) malloc(max) ; // allocate buffer
if (name == 0) quit();
printf("Please enter your first name:\n");
while (true) { // skip leading whitespace
int c = getchar();
if (c == EOF) break; // end of file
if (!isspace(c)) {
ungetc(c,stdin);
break;
}
}
int i = 0;
while (true) {
int c = getchar() ;
if (c == '\n' || c == EOF) { // at end; add terminating zero
name[i] = 0;
break;
}
name[i] = c;
if (i== max-1) { // buffer full
max = max+max;
name = (char*)realloc(name, max) ; // get a new and larger buffer
if (name == 0) quit() ;
}
i++;
}
printf("Hello %s\n",name);
free(name) ; // release memory
return 0;
}
The two programs are not exactly equivalent: the C++ style first program only reads a single “word” of input, while the C program skips whitespace and then reads a complete line of input. But it illustrates what's involved for doing this yourself. In short, better use C++ style. ;-)
Allocate an array with space for 1 or more characters. Read characters from your input source into the array until the array runs out of space, or you reach your terminating character. If you ran out of space, allocate a new array twice the size, copy the characters over, and deallocate the old array. Then go back to reading characters again. Repeat until you reach your terminating character (or whatever other condition you want to stop at).
You need to either store the whole user string in a temporary buffer with a max size, or read the input character by character.
Note that since you are using C++, it probably doesn't make any sense to allocate the memory manually: you could use std::string instead.
I am new to programming and attempted to improve on my basic countdown timer. I don't know why I'm getting this error and other questions are in different situations and therefore don't suit my program.
//countdown timer using while loops, if else, strings and sleep
#include <iostream>
#include <windows.h>
#include <string>
using namespace std;
int main ()
{
char progend[5];
float a; /* a will be floating point */
cout << "Enter start the the number you want to count down from" << ".\n";
while (a>-1) { /* the main program is located here */
cin >> progend[5];
if (progend[5] = "end") /* if the user inputs end the program ends */
{
a = -1;
}
else if (progend [5] = "start")
{
cin >> a;
while (a>0) { /* the actual countdown timer*/
Sleep(100);
a = a - 0.1;
cout << a;
}
cout << "Finished!" << ".\n" << "Enter start then enter another number to count down from or enter end to close the program" << ".\n";
}
else
{
cout << "Enter yes or end";
}
}
return 0;
}
Any help would be appreciated.
char progend[5];
...
if (progend [5] = "start")
tries to assign string literal "start" to 6th character of progend array (which doesn't even exist). Note that even if this code tried to assign a character, writing into the array after its end would cause undefined behavior.
You could either use C-style strcmp:
if (strcmp(progend, "start") == 0)
or yet even better: since this is C++, use std::string objects instead:
std::string progend;
...
if (progend == "start") ... // <-- this will use std::string::operator==
You're trying to assign a char* to char, I'm assuming you want to compare .
So use strstr
if (strstr(progend,"end" )){
//...
}
Similarly all other places
But why not use std::string , when using C++
std::string progend;
if(progend.find("end") != std::string::npos)
{
}
You are assigning a const char * to a char variable in
if (progend[5] = "end")
progend[5] is an element of a char array that holds a char value. "end" cannot be assigned to it.
You can use std::string. Then compare it like
std::string progend;
...
if(progend == "end")
{
//your code
You made a number of different errors.
cin >> progend[5];
Here, you ask for a character input, instead of a string. What is more, index 5 is out of the bounds of the array (we start counting from 0).
progend[5] = "start"
Here, there are two errors. To compare for equality, you sholud use == instead of =. What you actually did is try to assign a value. What is more, "start" is a C-type String, or better a pointer to the first character of the String.
Why don't you simply use a String from the C++ STL?
#include <string>
using namespace std;
// etc.
String progend;
Also, replace all instances of progend[5] with progend, you are not refering to a specific position. Equality check must also be ==.
I hope this helps!!! :D
I am currently writing a command line "parser" so to speak, and so far it has been working until I tried a few ways to add options/parameters.
void parser::nextCom() {
cout << parser::prompt; // parser::prompt = "> "
string com;
getline(cin, com);
char the_command[5]; // i want this to store the command e.g. "go" given that go is a command
for (int i = 0; i < com.size(); i++) {
if (com[i] == ' ') break;
else the_command[i] = com[i];
}
cout << the_command << endl;
}
The command is copied but some very unwanted characters show up when in print the_command to the console.
This is what I get if I pass "go north" as a command:
goÌÌÌÌÌÌÌÌÌÌÌÌÌÌØNi
I am not too sure about char arrays in C++, but I don't know how I am getting this output. Any help at all will be appreciated. Any questions about the code or if you need more of my code, just comment, thanks in advance
cout << the_command << endl;
When you print a char array like this, characters continue to be inserted until the null character \0 is found in the string.
Before you start copying characters from com to the_command, the array is completely uninitialized. I'll represent these unknown characters with question marks (but of course, they're probably not actually question marks):
? ? ? ? ?
This means you have no idea what the values of the chars in the array will be. You then copy only the characters g and o from the_command into com, so your array now contains:
g o ? ? ?
So when you attempt to output this array, the output stream doesn't know when to stop. You need to make sure you insert an \0 after the o. One way to do that would be:
for (int i = 0; i < com.size(); i++) {
if (com[i] == ' ') {
the_command[i] = '\0';
break;
}
else the_command[i] = com[i];
}
This will leave the array like so:
g o \0 ? ?
However, you'd be much better off just sticking to std::string. I don't want to think about the trouble you'll have with this array that could just be avoided. Here's how I would write your function:
void parser::nextCom() {
std::cout << parser::prompt;
std::string command_line, command;
std::getline(cin, command_line);
std::stringstream command_line_stream(command_line);
command_line_stream >> command;
if (command == "go") {
std::string direction;
command_line_stream >> direction;
go(direction);
}
}
You're not null-terminating the_command after the last character is read. Or doing any bounds checking.
Please, use std::string instead.
Change the code to:
if (com[i] == ' ')
{
com[i] = '\0';
break;
}
This will ensure there is a null terminator at the end of your char array. The reason you are seeing garbage is because std::cout will happily print characters until it sees a null terminator.
this is because you have a buffer overflow in your code. you copied an indeterminate length string into a char[5] buffer... basically, your loop is copying as many bytes as determined by the input string, into past the end of the char[5] array, which is no longer null terminated, so "cout" is just reading until it finds null bytes.
Basically the_command[5] contains garbage since is not initialized and doesn't contains the character terminator. You can clear it first, and you'll be fine
for (i = 0; i < 5; i++) {
the_command[i] = 0;
}