Hello everyone I'm having trouble with strlen and arrays, it keeps saying my string length is only one? If anyone could help it would be great here's my code:
#include <iostream>
using namespace std;
#include <cstring>
int main()
{
char word1[20];
int len = strlen(word1);
cout << "enter a word!\n";
cin.get(word1, 20, '\n'); cin.ignore(50,'\n');
cout << len;
}
Just read the back and forth in the comments, updating my answer to try and give some more intuition behind what's going on.
char word1[20]; Sets a place in your computer's memory that can eventually be filled by data up to 20 characters. Note that this statement alone does not "clear" the memory of whatever is currently there. As sfjac has pointed out, this means that literally anything could be in that space. It's highly unlikely that whatever is in this space is a character or anything your code could readily understand.
int len = strlen(word1); Creates an integer and sets it equal to the value of the number of characters currently in word1. Note that, because we have not specified any content for word1, you're taking the length of whatever happened to be in that memory space already. You've limited the maximum to 20, but in this case, whatever data junk is in there is giving you a length of 1.
cout << "enter a word!\n"; Prompt the user for a word
cin.get(word1, 20, '\n'); cin.ignore(50,'\n'); Get the word, store it in word1. At this point, word1 is now defined with actual content. However - you've already defined the variable len. The computer does not know to automatically redefine this for you. It follows the steps you provide, in order.
cout << len; Print the value stored in len. Because len was created prior to the user entering their data, len has absolutely nothing to do with what the user entered.
Hope this helps give you some intuition that will help beyond this one question!
#Chris is correct but perhaps a small explanation. When you declare a character array like char word1[20] on the stack, the array will not be initialized. The strlen function computes the length of the array by counting the number of characters from the address of word1 to the first null byte in memory, which could be pretty much anything.
I highly recommend using std::string for text.
If you must use character arrays:
Define a named identifier for the capacity.
Define the array using the named identifier.
The capacity should account for a terminating nul, '\0', character to
mark the end of the maximum text length.
Using the above guidelines you have the simple program:
int main(void)
{
std::string a_word_string;
std::string line_of_text_string;
const unsigned int c_string_capacity = 32U;
char c_string[c_string_capacity];
// The std::string functions
cout << "Enter some text: ";
getline(cin, line_of_text_string); // read a line of text
cout << "\nEnter a sentence: ";
cin >> a_word_string;
cin.ignore(10000, '\n'); // Ignore remaining text in the buffer.
// The C-style string functions
cout << "Enter more text: ";
cin.read(c_string, c_string_capacity);
c_string[c_string_capacity - 1] = '\0'; // Insurance, force end of string character
cout << "You entered " << (strlen(c_string)) << " characters.\n";
return EXIT_SUCCESS;
}
The std::string class is more efficient and can handle dynamically size changes.
The length of the array is the value of c_string_capacity which was used when defining the array.
The length of the text in the array is defined as strlen(c_string), which is the number of characters before the terminating nul is found.
You have to calculate len after reading in word1, otherwise you are left with undefined behaviour.
char word1[20];
cout << "enter a word!\n";
cin.get(word1, 20, '\n'); cin.ignore(50,'\n');
int len = strlen(word1);
cout << len;
It's a good idea to always initialize objects when you declare them. Since objects inside of a scope are not guaranteed to be initialized.
In C++11 for example, you can do this:
char arr[10]{}; // this will initialize the objects in the array to default.
char arr[10]{0}; // the same.
Related
I was using character arrays to get inputs from the user then display the output afterwards. However, every time I enter values with spaces in between, only the first word before the space is printed.
For instance, this is what I typed:
Customer No.: 7877 323 2332
This will be the output:
Customer No.: 7877
I already searched for possible solutions but I can't seem to find the right solution.
This is my code for reference:
#include<iostream>
using namespace std;
int main()
{
char custNum[10] = " "; // The assignment does not allow std::string
cout << "Please enter values for the following: " << endl;
cout << "Customer No.: ";
cin >> custNum;
cout << "Customer No.: " << custNum << endl;
}
Another option is to use std::basic_istream::getline to read the entire string into the buffer and then remove the spaces with a simple for loop. But when using plain-old character arrays don't skimp on buffer size. It is far better to be 1000-characters too long than one-character too short. With your input, your absolute minimum size of custNum is 14 characters (the 13 shown plus the '\0' (nul-terminating) character. (rough rule-of-thumb, take your longest estimated input and double it -- to allow for user-mistake, cat stepping on keyboard, etc...)
In you case you can simply do:
#include <iostream>
#include <cctype>
int main() {
char custNum[32] = " "; // The assignment does not allow std::string
int wrt = 0;
std::cout << "Please enter values for the following:\nCustomer No.: ";
if (std::cin.getline(custNum, 32)) { /* validate every input */
for (int rd = 0; custNum[rd]; rd++)
if (!isspace((unsigned char)custNum[rd]))
custNum[wrt++] = custNum[rd];
custNum[wrt] = 0;
std::cout << "Customer No.: " << custNum << '\n';
}
}
The two loop counters rd (read position) and wrt (write position) are simply used to loop over the original string and remove any whitespace found, nul-terminating again when the loop is left.
Example Use/Output
$ ./bin/readcustnum
Please enter values for the following:
Customer No.: 7877 323 2332
Customer No.: 78773232332
Also take a look at Why is “using namespace std;” considered bad practice? and C++: “std::endl” vs “\n”. Much easier to build good habits now than it is to break bad ones later... Look things over and let me know if you have questions.
Apart from std::getline, if you are going to use C-style strings, try the following code:
int main() {
char* str = new char[60];
scanf("%[^\n]s", str); //accepts space a a part of the string (does not give UB as it may seem initially
printf("%s", str);
return 0;
}
Also, if you absolutely need it to be a number, then use atoi
int ivar = std::atoi(str);
PS Not to forget gets (!!dangerous!!)
char* str;
gets(str);
puts(str);
cin >> int_variable will stop reading input when it reaches the first character that isn't a valid part of a number. C++ does not consider spaces part of a number, so it stops reading as soon as it encounters one.
You could use std::getline to read into a string instead, then remove the spaces from the string before converting to an integer. Or maybe in this case you don't even need the integer and can leave it as a string.
I can't understand why char *ptr = new char[7] would not truncate an input of data bigger than 7 characters. Also why eighter char c[7] would let me input more than 6 characters (but giving error when attributing it a literal value of more than 6 characters).
Doing it with malloc function seems a little bit to hard for me for a moment, this is why i prefer not to use it. I would prefer for the moment not to use it.
char qs[7] = "1234567"; //error too many
char qs2[7];
cin >> qs2; //input 123456789
cout << qs2; //out same as input, expecting 123456
char *qs3 = new char[7];
cin >> qs3; //input 123456789
cout << qs3; //out same as input, expecting 123456
The input stream, currently, only takes a pointer as an argument. Therefore it cannot know the size of the buffer that it fills. Therefore it cannot know whether it should truncate or not. Reading a string longer than the buffer will cause the buffer to overflow, and behaviour of the program will be undefined. Don't do it.
Since C++20, the array operand is passed by reference, and the operation does know the size and will truncate the input. This won't help in the case of qs3 however, since it is only a pointer rather than an array.
Instead, you can use:
std::cin.get(qs3, 6);
qs3[6] = '\0';
To ensure that no more characters are read than fit the buffer.
Or if you prefer to not truncate input, then you can read into std::string.
Doing it with malloc function seems a little bit to hard for me for a moment, this is why i prefer not to use it.
Good. It wouldn't solve your problem, and there is no need to use it, nor is there any advantage to using it either.
The both code snippets
char qs2[7];
cin >> qs2; //input 123456789
cout << qs2; //out same as input, expecting 123456
char *qs3 = new char[7];
cin >> qs3; //input 123456789
cout << qs3; //out same as input, expecting 123456
have undefined behavior. The memory beyond the allocated arrays is overwritten. The consequence can be of any kind.
Consider the following demonstrative program.
#include <iostream>
int main()
{
char gs1[7] = "123456";
char gs2[7];
char gs3[7] = "ABCDEF";
std::cin >> gs2;
std::cout << '\n';
std::cout << gs1 << '\n';
std::cout << gs2 << '\n';
std::cout << gs3 << '\n';
return 0;
}
If to enter
1234567
then the program output might look like
123456
1234567
As you can see the string "ABCDEF" was not outputted. It is the result of that the terminating zero '\0' that was appended to the array gs2 after this statement
std::cin >> gs2;
overwrites the first character of the array gs3. Now it content looks like
{ '\0', 'B', 'C', 'D', 'F', '\0' }
So as the first element of the array is the terminating zero then the empty string was being outputted in this statement
std::cout << gs3 << '\n';
The C-strings are zero-terminated, that mean you should always allocate buffer with size string length + 1.
char qs[7] = "1234567"; //error too many
In statically allocated buffers it is obvious for the compiler that your buffer does not have space for terminating zero. This should be char qs[8].
In both other examples, the operator takes pointer to buffer as argument and there is no way for it to know how large it is. It just fill it until the end of input. You get classic buffer overrun situation, and you are lucky that there is nothing important out there (after the buffer boundaries).
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'm reading C++ Primer Plus (6th Edition) and I've come across some sample code in chapter 4 which I have a question about:
Listing 4.2 strings.cpp
// strings.cpp -- storing strings in an array
#include <iostream>
#include <cstring> // for the strlen() function
int main()
{
using namespace std;
const int Size = 15;
char name1[Size]; // empty array
char name2[Size] = "C++owboy"; // initialized array
// NOTE: some implementations may require the static keyword
// to initialize the array name2
cout << "Howdy! I'm " << name2;
cout << "! What's your name?\n";
cin >> name1;
cout << "Well, " << name1 << ", your name has ";
cout << strlen(name1) << " letters and is stored\n";
cout << "in an array of " << sizeof(name1) << " bytes.\n";
cout << "Your initial is " << name1[0] << ".\n";
name2[3] = '\0'; // set to null character
cout << "Here are the first 3 characters of my name: ";
cout << name2 << endl;
return 0;
}
The code itself doesn't cause any confusion, but I've been running it through and I'm confused by a certain scenario.
name1 is initialised as an array of chars 15 elements in length - am I right in thinking this should hold a string 14 characters in length? The end char should be reserved for the string terminator, right?
If I enter my name as HowCanIPossiblyFitThisEntireStringIn?, I get the following output:
Howdy! I'm C++owboy! What's your name?
HowCanIPossiblyFitThisEntireStringIn?
Well, HowCanIPossiblyFitThisEntireStringIn?, your name has 37 letters and is stored
in an array of 15 bytes.
Your initial is H.
Here are the first 3 characters of my name: C++
How is the entire name I enter being stored? If I step through the code, after cin reads into name1, Visual Studio tells me it contains elements 0 - 14, with the last one being the char 'y' ("HowCanIPossibly...). I would assume from this that any extra data entered had been truncated and lost, but this is obviously not the case as the following cout successfully writes the entire name out to the console.
For curiosity's sake, could anyone enlighten me as to what's happening here? For the record, I'm using Visual Studio 2012 Express.
You are writing past the bounds of the array. The C++ standard doesn't say this should be an error; it says it is undefined behaviour. This means anything can happen, including seemingly working correctly. Simply put, your code does not have well-defined behaviour and so you shouldn't trust it to work.
We can imagine why it's probably working though. The first 15 characters will fit nicely into the array:
|H|o|w|C|a|n|I|P|o|s|s|i|b|l|y|F|i|t|T|h|i|s|E|n|t|i|r|e|S|t|r|i|n|g|I|n|?|...
^ ^
| These characters fit |
in the array
The rest of the characters are being written to the following memory locations. Now, remember that the null character, which is used to terminate C-style strings, is defined to have a representation that is all 0 bits. Now if the location following the location that contains the ? has all 0 bits in it, the string will appear to be null-terminated.
But the fact is, this is undefined. It just happens to work. Unfortunately, this is the scariest type of bug because it can seemingly work for a long time until one day you start getting calls from your very, very angry client.
You could use istream::get with the buffer and the size of the buffer:
cin.get(name1, Size);
As others have noted, it's far easier to use std::string:
std::string name1;
cin >> name;
I've come this far without asking for help, but I've got a problem that I can't seem to fix. I like cryptology, so now that I am learning C++, I want to make programs to encrypt and decrypt strings. I read that the best way is to convert the text to ASCII and go from there, so here is a simple program I made in C++ to try and convert a char variable to ASCII:
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
int main()
{
char strString[1000];
cout<<"Enter you message:"<<endl;
cin>>strString[1000];
string strEncrypt;
int a = 0;
while (strString != '\0')
{
int b = (int)strString[a];
strEncrypt.at(a) = b; //This is where I'm getting an error.
a++;
}
cout<<"Encrypted message:"<<endl;
cout<<strEncrypt<<endl;
}
So, I've tried all 3 things I know to do to troubleshoot (Google, check for missing simicolons, and make sure I'm doing == not =, but this is just something I don't know how to do, not something I'm forgetting (I hope). So, any help would great!
You don't have to change the characters to ASCII they already are. Chars are basically the same as integers in memory.
Now to your question; . If you want to set a character in a string you can do that like this
string[index] = b;
Another thing to be careful for in your code. You are using cin to read the string from the user. This will not let you read messages that have spaces in them and will only read the first word. For example, if the user enters "Love Crypto" cin will only read "Love" and "Crypto" will be ignored. To get the entire line, use getline instead.
As for looping over characters in a string, it's better to do it as follows:
for(int i = 0; i < strString.length(); i++)
{
strString[i] = bla;
}
Again, you're code isn't actually doing anything. It is only reading a letter and then storing a "letter" in another string.
string::at() throws exception if the index passed to at() is out of range. So, if you are getting runtime error then it's expected. Because, your string strEncrypt is initialized to "" and thus the size is 0.
You may try
strEncrypt.reserve(strlen(strString));
Easiest way to actually make the code you have work is change this line strEncrypt.at(a) = b; to this strEncrypt += b; Which will add the characters to the empty string strEncrypt.
Your code doesn't make much sense though as char types are already ascii. You'll have to explain more about what kind of encrypting you are trying to do and maybe we can point you in the right direction.
EDIT: After thinking about what you're trying to do a bit more based on the code you have it seems like you want to print the numeric ascii value of characters. You can do that with just a cast like this:
string input;
cout << "Enter you message:" << endl;
// handle spaces in the message
getline(cin, input);
cout << "String chars as ascii values:" << endl;
cout << "Char: " << "ASCII Code:" << endl;
for (int i = 0; i < input.length(); ++i)
{
// casting the char to an int with (int) will print the ascii code
cout << input[i] << " " << (int)input[i] << endl;
}
On top of the fact that your input is already in ASCII, keep in mind that doing cin >> strString[1000] doesn't limit the input captured to the length of your buffer unless you specifically specify the number of characters to capture for the stream object using setw() or setting it's ios_base::width data member. So your method right now risks buffer overflows.
Secondly, the form of cin >> that you're using will not capture the entire line of input. Instead it will stop at the first white-space or any other delimiting character (or end-of-file if that is reached first). In your case, if you are entering a line like "Hello World", then the syntax you're using will only capture "Hello" and drop "World".
A much better idea would be to use the getline() function with a std::string object if you are wanting to capture a line of input to a string and remove the delimiting newline character without risking buffer overflows ... for instance:
string strString;
getline(cin, strString);
Apart from advises given, when receiving this kind of run-time errors use Cppcheck utility.
It will give you the answer: "Message: Array 'strString[1000]' index 1000 out of bounds".