Able to Access Elements with Index Greater than Array Length - c++

The following code seems to be running when it shouldn't. In this example:
#include <iostream>
using namespace std;
int main()
{
char data[1];
cout<<"Enter data: ";
cin>>data;
cout<<data[2]<<endl;
}
Entering a string with a length greater than 1 (e.g., "Hello"), will produce output as if the array were large enough to hold it (e.g., "l"). Should this not be throwing an error when it tried to store a value that was longer than the array or when it tried to retrieve a value with an index greater than the array length?

The following code seems to be running when it shouldn't.
It is not about "should" or "shouldn't". It is about "may" or "may not".
That is, your program may run, or it may not.
It is because your program invokes undefined behavior. Accessing an array element beyond the array-length invokes undefined behavior which means anything could happen.
The proper way to write your code is to use std::string as:
#include <iostream>
#include <string>
//using namespace std; DONT WRITE THIS HERE
int main()
{
std::string data;
std::cout<<"Enter data: ";
std::cin>>data; //read the entire input string, no matter how long it is!
std::cout<<data<<std::endl; //print the entire string
if ( data.size() > 2 ) //check if data has atleast 3 characters
{
std::cout << data[2] << std::endl; //print 3rd character
}
}

It can crash under different parameters in compilation or compiled on other machine, because running of that code giving undefined result according to documentaton.

It is not safe to be doing this. What it is doing is writing over the memory that happens to lie after the buffer. Afterwards, it is then reading it back out to you.
This is only working because your cin and cout operations don't say: This is a pointer to one char, I will only write one char. Instead it says: enough space is allocated for me to write to. The cin and cout operations keep reading data until they hit the null terminator \0.
To fix this, you can replace this with:
std::string data;
C++ will let you make big memory mistakes.
Some 'rules' that will save you most of the time:
1:Don't use char[]. Instead use string.
2:Don't use pointers to pass or return argument. Pass by reference, return by value.
3:Don't use arrays (e.g. int[]). Use vectors. You still have to check your own bounds.
With just those three you'll be writing some-what "safe" code and non-C-like code.

Related

Why is strlen(s) different from the size of s, and why does cout char display a character not a number?

I wrote a piece of code to count how many 'e' characters are in a bunch of words.
For example, if I type "I read the news", the counter for how many e's are present should be 3.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s[255],n,i,nr=0;
cin.getline(s,255);
for(i=1; i<=strlen(s); i++)
{
if(s[i-1]=='e') nr++;
}
cout<<nr;
return 0;
}
I have 2 unclear things about characters in C++:
In the code above, if I replace strlen(s) with 255, my code just doesn't work. I can only type a word and the program stops. I have been taught at school that strlen(s) is the length for the string s, which in this case, as I declared it, is 255. So, why can't I just type 255, instead of strlen(s)?
If I run the program above normally, it doesn't show me a number, like it is supposed to do. It shows me a character (I believe it is from the ASCII table, but I'm not sure), like a heart or a diamond. It is supposed to print the number of e's from the words.
Can anybody please explain these to me?
strlen(s) gives you the length of the string held in the s variable, up to the first NULL character. So if you input "hello", the length will be 5, even though s has a capacity of 255....
nr is displayed as a character because it's declared as a char. Either declare it as int, for example, or cast it to int when cout'ing, and you'll see a number.
strlen() counts the actual length of strings - the number of real characters up to the first \0 character (marking end of string).
So, if you input "Hello":
sizeof(s) == 255
strlen(s) == 5
For second question, you declare your nr as char type. std::cout recognizes char as a single letter and tries it print it as such. Declare your variable as int type or cast it before printing to avoid this.
int nr = 42;
std::cout << nr;
//or
char charNr = 42;
std::cout << static_cast<int>(charNr);
Additional mistakes not mentioned by others, and notes:
You should always check whether the stream operation was successful before trying to use the result.
i is declared as char and cannot hold values greater than 127 on common platforms. In general, the maximum value for char can be obtained as either CHAR_MAX or std::numeric_limits<char>::max(). So, on common platforms, i <= 255 will always be true because 255 is greater than CHAR_MAX. Incrementing i once it has reached CHAR_MAX, however, is undefined behavior and should never be done. I recommend declaring i at least as int (which is guaranteed to have sufficient range for this particular use case). If you want to be on the safe side, use something like std::ptrdiff_t (add #include <cstddef> at the start of your program), which is guaranteed to be large enough to hold any valid array size.
n is declared but never used. This by itself is harmless but may indicate a design issue. It can also lead to mistakes such as trying to use n instead of nr.
You probably want to output a newline ('\n') at the end, as your program's output may look odd otherwise.
Also note that calling a potentially expensive function such as strlen repeatedly (as in the loop condition) can have negative performance implications (strlen is typically an intrinsic function, though, and the compiler may be able to optimize most calls away).
You do not need strlen anyway, and can use cin.gcount() instead.
Nothing wrong with return 0; except that it is redundant – this is a special case that only applies to the main function.
Here's an improved version of your program, without trying to change your code style overly much:
#include <iostream>
#include <cstring>
#include <cstddef>
using namespace std;
int main()
{
char s[255];
int nr=0;
if ( cin.getline(s,255) )
{ // only if reading was successful
for(int i=0; i<cin.gcount(); i++)
{
if(s[i]=='e') nr++;
}
cout<<nr<<'\n';
}
return 0;
}
For exposition, the following is a more concise and expressive version using std::string (for arbitrary length input), and a standard algorithm. (As an interviewer, I would set this, modulo minor stylistic differences, as the canonical answer i.e. worth full credit.)
#include <algorithm>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
if ( getline(cin, s) )
{
cout << std::count(begin(s), end(s), 'e') << '\n';
}
}
I have 2 unclear things about characters in C++: 1) In the code above,
if I replace the "strlen(s)" with 255, my code just doesn't work, I
can only type a word and the program stops, and I have been taught at
school that "strlen(s)" is the length for the string s, wich in this
case, as I declared it, is 255. So, why can't I just type 255, instead
of strlen(s);
That's right, but strings only go the null terminator, even if there's more space allocated. Consider this, per example:
char buf[32];
strcpy(buf, "Hello World!");
There's 32 chars worth of space, but my string is only 12 characters long. That's why strlen returns 12 in this example. It's because it doesn't know how long the buffer is, it only knows the address of the string and parses it until it finds the null terminator.
So if you enter 255, you're going past what was set by cin and you'll read the rest of the buffer. Which, in this case, is uninitialized. That's undefined behavior - in this case it will most likely read some rubbish values, and those might coincidentally have the 'e' value and thus give you a wrong result.
2) If you run the program above normaly, it doesn't show you a number,
like it's supposed to do, it shows me a character(I believe it's from
the ASCII table but I'm not sure), like a heart or a diamond, but it
is supposed to print the number of e's from the words. So can anybody
please explain these to me?
You declared nr as char. While that can indeed hold an integer value, if you print it like this, it will be printed as a character. Declare it as int instead or cast it when you print it.

Reversing input, output string is unexpectedly empty

#include <iostream>
#include <string>
using namespace std;
int main()
{
string s1;
cin>>s1;
int n=s1.size();
string s2;
for(int a=0;a<n;a++)
{
s2[a]=s1[n-1-a];
}
cout<<s2;
}
However I am not getting any output, But I can print elements of reversed string. Can anybody please help.
string s2; // no size allocated
for(int a=0;a<n;a++)
{
s2[a]=s1[n-1-a]; // write to somewhere in s2 that doesn't exist yet
You are writing into elements of s2 that you never created. This is Undefined Behaviour, and anything may happen, including appearing to work normally. In this case, you are probably overwriting some random place in memory. It might crash, or that memory might really exist but not break anything else right away. You might even be able to read that back later, but it would only seem to work by pure accident.
You could catch this problem by always using s2.at(a) to access the data, as it will do a range check for you. ([] does not do a range check). There's a cost to this of course, and sometimes people will skip it in circumstances where they are certain the index cannot be out of bounds. That's debateable. In this case, even though you were probably sure you got the maths right, it still would have helped catch this bug.
You need to either create that space up front, i.e. by creating a string full of the right number of dummy values, or create the space for each element on demand with push_back. I'd probably go with the first option:
string s2(s1.size(), '\0'); // fill with the right number of NULs
for(int a=0;a<n;a++)
{
s2.at(a)=s1.at(n-1-a); // overwrite the NULs
You might want to choose a printable dummy character that doesn't appear in your test data, for example '#', since then it becomes very visible when you print it out if you have failed to correctly overwrite some element. E.g. if you try to reverse "abc" but when you print it out you get "cb#" it would be obvious you have some off-by-one error.
The second option is a bit more expensive since it might have to do several allocations and copies as the string grows, but here's how it would look:
string s2; // no space allocated yet
for(int a=0;a<n;a++)
{
s2.push_back(s1.at(n-1-a)); // create space on demand
I assume you are doing this as a learning exercise, but I would recommend against writing your own reverse, since the language provides it in the library.
You are utilizing something called Undefined Behaviour in your code. You try to access element of s2 at a position, but your string does not have that many chars (it's empty).
You can use std::string::push_back function to add a character on the last postion, so your code would look like this:
for(int a=0;a<n;a++)
{
s2.push_back(s1[n-1-a]);
}
EDIT, to address the other question, your console window probably closes before you can notice. That's why "you don't get any output".
Try this: How to stop C++ console application from exiting immediately?
You can use the inbuilt reverse function in c++
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s1 = "string1";
reverse(s1.begin(),s1.end());
cout << s1;
return 0;
}
Hope that helps :)
You can just construct the string with reverse iterators:
std::string reverse ( std::string const& in )
{
return std::string { in.crbegin(), in.crend() };
}

C++ strlen() initialized char array

Quick question.
I couldn't find why an initialized char array returns this value. I understand that the strlen() function will only return the amount of characters inside of an array, and not the size, but why will it return 61 if there are no characters in it?
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
const int MAX = 50;
char test[MAX];
int length = strlen(test);
cout << "The current \'character\' length of the test array is: " << length << endl;
// returns "61"
// why?
cin >> test; //input == 'nice'
length = strlen(test);
cout << "The new \'character\' length of the test array is: " << length << endl;
// returns 4 when 'nice' is entered.
// this I understand.
return 0;
}
This was driving me nuts during a project because I would be trying to use a loop to feed information into a character array but strlen() would always return an outrageous value until I initialized the array as:
char testArray[50] = '';
instead of
char testArray[50];
I got these results using Visual Studio 2015
Thanks!
I think the basic misunderstanding is that - unlike in other languages - in C, locally defined variables are not initialised with any value, neither with empty strings, nor with 0, nor with any <undefined> or whatever unless you explicitly initialise them.
Note that accessing uninitialised variables actually is "undefined behaviour"; it may lead to "funny" and non-deterministic results, may crash, or might even be ignored at all.
A very common behaviour of such programs (though clearly not guaranteed!) is that if you write
char test[50];
int length = strlen(test);
then test will point to some memory, which is reserved in the size of 50 bytes yet filled with arbitrary characters, not necessarily \0-characters at all. Hence, test will probably not be "empty" in the sense that the first character is a \0 as it would be with a really empty string "". If you now access test by calling strlen(test) (which is actually UB, as said), then strlen may just go through this arbitrarily filled memory, and it might detect a \0 within the first 50 characters, or it might detect the first \0 much after having exceeded the 50 bytes.
It's good that you have found your answer, but you have to understand how does this thing works, I think.
char test[MAX];
In this line of code you have just declared an array of MAX chars. You will get random values in this array until you initialize it. The strlen function just walks through the memory until it find 0 value. So, since values in your array are random, the result of this function is random. Moreover, you can easily walk outside of your array and get UB.
char test[MAX] = '';
This code initilizes the first element in 'test' array with 0 value so strlen will be able to find it.

Program crashes when using string instead of char array

I was trying to write a program to enter texts like passwords (display "*" instead of the character which in input by the user).
The problem is, when I use char arrays to store the password, the program works fine, but when I use a string class variable for the same purpose, my program crashes while displaying the string.
Here is the code:
// *********THIS CODE WORKS FINE***********
#include <iostream>
#include<string>
#include<conio.h>
int main()
{
using namespace std;
int i=0;
cout<<"Enter a password,press ENTER to finish writing"<<endl;
char passw[20];
passw[i]=getch();
while(passw[i]!=13)
{
i++;
cout<<"*";
passw[i]=getch();
}
passw[i+1]='\0';
cout<<"\nPassword is "<<passw;
return 0;
}
Now when I replace char passw[20] with string passw:
//**********THIS CODE CRASHES!!*********
#include <iostream>
#include<string>
#include<conio.h>
int main()
{
using namespace std;
int i=0;
cout<<"Enter a password,press ENTER to finish writing"<<endl;
string passw;
passw=getch();
while(passw[i]!=13)
{
i++;
cout<<"*";
passw[i]=getch();
}
cout<<"\nPassword is "<<passw;
return 0;
}
Can anybody explain why this is happening?
Just started with strings and there's just too much for me to know about strings :)
In string you can use string concatenation.
you can save your char and add it to your string variable.
char ch;
string pass;
ch=getch();
pass=pass+ch;
You're accessing a location (passw[i]) that is not yet existing in your std::string and you're not storing it correctly to a string. You should use the method passwd.push_back(char) to store it.
Check for reference: http://en.cppreference.com/w/cpp/string/basic_string/push_back
A string works differently compared to a char array. You probably know that char passw[20] in your first example creates an array with space for up to 20 chars. These can then be accessed using operator[] without a problem. A string, unlike a basic array, is a dynamic data structure, meaning it grows and shrinks over time as your program runs. Its content can also be accessed using operator[], however, this will not append to the string, it can only be used to change what is already there.
It's important to note that in c++, not all operations will perform what is known as bounds checking. In your second example, you access the i-th character of your string and write a character to that location. However, what would happen if you try to write, for instance, to the 10-th character of a string that only has space for 5? When doing so via operator[], the program will write to whatever location the 10-th character would be at, even though that part of memory is actually not part of the string. Anything could be there and will be overwritten by that operation. As you can probably imagine, this is not desirable at all and can lead to all sorts of problems later down the line. If you're lucky, your program will crash immediately on the write. It did not in your case, however, that's not a good thing; writing out of bounds can cause a heap corruption (the heap being a certain part of memory) which generally leads to a crash at some point down the line.
It's fine to use operator[] to change a strings characters if and only if you know whatever index you're accessing is within the strings size. Otherwise, you need to append to the string using an appropriate member function. These will enlarge the string if necessary.
You always need to pay attention when working with dynamic memory and what parts of it you're accessing (in your first example, for instance, you would also write out of bounds if your password is too long).

Why does this C++ char array seem to be able to hold more than its size?

#include <iostream>
using namespace std;
typedef struct
{
char streetName[5];
} RECORD;
int main()
{
RECORD r;
cin >> r.streetName;
cout << r.streetName << endl;
}
When I run this program, if I enter in more than 5 characters, the output will show the whole string I entered. It does not truncate at 5 characters. Why is that?
How can I get this to work correctly?
You are overflowing the buffer. Put another char array after streetName and you will likely find that it gets the rest of the characters. Right now you are just corrupting some memory on your stack.
In order to limit the input to the size of the receiving array you need to use the length-limiting facilities provided by your input method. In your case you are using cin, which means that you can specify the limit by using its width method
cin.width(5);
cin >> r.streetName;
Because cin sees streetName as a char * and writes to memory and there is nothing to stop writing to *(streetName + 6) and further. This is a form of buffer overrun
The best code in this case is define streetName as a std::string
i.e.
typedef struct
{
std::string streetName;
} RECORD;
Because you're overruning the end of your buffer and in this particular case you're getting away with it. C and C++ make it very easy to "shoot yourself in the foot", but that doesn't mean that you should.
It's a buffer overrun.
C++ does not perform bounds checking on array accesses, and memory does not simply stop at the end of the array. You are writing data to memory that is not part of the array, the consequences of which are non-deterministic, and may sometimes even appear to work.
It is quite likely that if you placed that code into a function, the program would crash when you tried to return from the function, because one likely possibility is that you will have dumped on the function return address on the stack. You may also have corrupted data belonging to the calling function.
The way to do this correctly in c++ is to use a std::string.
#include<iostream>
#include<string>
....
std::string r;
getline(cin, r);
std::cout << r <<std::endl;
For truncated input(with suitably defined and inited values).
while(cin.peek() != EOF && i < len)
{
cin >> arr[i];
++i;
}
You will want to do something after this to flush the buffer and not leave the rest of the line sitting on the input stream if you plan on doing other things with it.