Purpose of char a[0] in converting integer to string using itoa() - c++

I have this code,
char a[0];
cout << "What is a? " << a << endl;
char *word = itoa(123,a,10);
string yr = string(word);
but i have trouble comprehending the array a[0]. I tried to change its value and see if there is any changes, but it seems to make no differences at all.
example, even if a change a[0] to a[1], or any other integer, the output still make no difference
char a[1];
cout << "What is a? " << a << endl;
char *word = itoa(123,a,10);
string yr = string(word);
What is its purpose here?

Since itoa function is non-standard, this is a discussion of a popular signature itoa(int, char*, int).
Second parameter represents a buffer into which a null-terminated string representing the value is copied. It must provide enough space for the entire string: in your case, that is "123", which takes four characters. Your code passes a[] as the buffer, but the size of a[] is insufficient to accommodate the entire "123" string. Hence, the call causes undefined behavior.
You need to make a large enough to fit the destination string. Passing a buffer of size 12 is sufficient to accommodate the longest decimal number that can be produced by itoa on a 32-bit system (i.e. -2147483648). Replace char a[0] with char a[12] in the declaration.

What is its purpose here?
A zero-length array is an array with no elements in it.
You can't [legally] print or modify its contents, because it doesn't have any.
There are arcane reasons to want to use one, but speaking generally it has no purpose for you. It's not even allowed by the standard (although compilers tend to support it for those arcane reasons).
even if a change a[0] to a[1], or any other integer, the output still make no difference
Well, if you have an array with n elements in it, and you write more than n elements' worth of data to it, that's a "buffer overrun" and has undefined behaviour. It could appear to work as you overwrite somebody else's memory, or your program could crash, or your dog could suddenly turn into a zombie and eat you alive. Best avoided tbh.

Related

Is character array size dynamic in C/CPP/C++?

My knowledge till now was that arrays in C and CPP/C++ have fixed sizes. However recently I encountered 2 pieces of code which seems to contradict this fact. I am attaching the pics here. Want to hear everyone's thoughts on how these are working. Also pasting the code and doubts here:
1.
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char str1[]="Good"; //size of str1 should be 5
char str2[]="Afternoon"; //size of str2 should be 10
cout<<"\nSize of str1 before the copy: "<<sizeof(str1);
cout<<"\nstr1: "<<str1;
strcpy(str1,str2); //copying str1 into str2
cout<<"\nSize of str1 after the copy: "<<sizeof(str1);
cout<<"\nstr1: "<<str1;
return 0;
}
your text
O/P:
Size of str1 before the copy: 5
str1: Good
Size of str1 after the copy: 5
str1: Afternoon
In first snippet I am using strcpy to copy char str2[] contents that is "Afternoon" into char str1[] whose size is 5 less than size of str2. So theoritically the line strcpy(str1,str2) should give error as size of str1 is less than size of str2 and fixed. But it executes, and more surprising is the fact that even after str1 contain the word "afternoon" the size is still the same.
2.
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char first_string[10]; // declaration of char array variable
char second_string[20]; // declaration of char array variable
int i; // integer variable declaration
cout<<"Enter the first string: ";
cin>>first_string;
cout<<"\nEnter the second string: ";
cin>>second_string;
for(i=0;first_string[i]!='\0';i++);
for(int j=0;second_string[j]!='\0';j++)
{
first_string[i]=second_string[j];
i++;
}
first_string[i]='\0';
cout<<"After concatenation, the string would look like: "<<first_string;
return 0;
}
O/P:
Enter the first string: good
Enter the second string: afternoon
After concatenation, the string would look like: goodafternoon
Here also even if I provide a string of length 20 as input to second_string[] it's still able to concatenate both the strings and put them in first_string[], even though the size of the concatenated string will be clearly greater than size of first_string[] which is 10.
I tried to assign a string of greater length to a string variable of smaller length. techincally it should not work but it worked anyway
There are two misunderstandings here
sizeof is the size of the array at compile time. It has nothing to do with the contents of the array. You can change the contents all you like and sizeof will still be the same. If you want the length of a string use the function strlen.
Most of the time when you break the rules of C++ it leads to undefined behaviour. Copying a string into an array that is too small to hold that string is one example of undefined behaviour.
You said
So theoritically the line strcpy(str1,str2) should give error as size
of str1 is less than size of str2 and fixed.
This is untrue. Undefined behaviour does not mean that there must be an error. It means exactly what it says, the behaviour of your program is undefined, anything could happen. That might mean an error message, or it might mean a crash, or it might mean that your program seems to work. The behaviour is undefined.
You aren't alone in thinking as you did. I reckon the purpose of sizeof and the nature of undefined behaviour are two of the commonest beginner misunderstandings.
And to answer the question in the title. The size of a character array is fixed in C++, nothing in your example contradicts that.
I've honestly never seen a C++ programmer write char stringname[20] = "string";, that just isn't the way you'd handle strings in C++⁰.
And neither would a C programmer use array notation, because well, it's just not common; you'd typically use arrays for things that aren't strings, even if the type of a "string literal" is actually char[length + 1].
Your access beyond the end of an array is simply a bug. It is undefined behaviour. A buffer overflow. A static code analyzer, quite possibly even a compiler, would tell you that this is a mortal sin. The str* functions know literally nothing about the size of your array, they only see a pointer to the first element, and your array literally knows nothing about the length of the string it contains, which is given by the terminating zero character's position. You're mixing up two things here!
In C++, you'd definitely use the std::string class to read from cin, exactly to avoid the problem with buffer overflows.
So, honestly: If you're a C++ beginner, maybe try to ignore C strings for now. It's not a C++ way of dealing with string data other than fixed string literals (i.e., things between "" in your source code), and the C way of string handling is literally still the dominant cause for remote-exploitable bugs in software, far as I can tell. C++ is not C, and, honestly, when it comes to handling strings, for the better. Including both <string.h> and <iostreams> is a pretty reliable indication of a programming beginner who has access to bad guides that treat C++ as extended C. But that's simply not true; it's a very different programming language with some far-reaching C compatibility, but you would, and should, not mix these two languages – as a beginner, it's hard enough to learn one¹.
⁰ Technically speaking, it even feels wrong; a string literal in C++ is a const char pointer, whereas it's just a char pointer in C. C and C++ are not the same language.
¹If you feel like you're explaining C++ to people, and sometimes feel overwhelmed with making a good explanation for things to people who are not expert C programmers already, Kate Gregory made a nice talk why teaching C to teach C++ is a really bad idea, which I agree to, even if she overstresses a few points.

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.

cin >> writing out of range?

I have a code
char s[5];
cin >> s;
cout << strlen(s);
cout << endl;
cout << s;
It works even if I input more than 5 chars, for example "qwertyui". Does it mean that I am using not allocated memory?
strlen(s)
is something, but has nothing to do with 5. strlen applies to C strings, which are char arrays, but their length is defined as the numbers of characters until the first zero byte happens.
Now, cin in your second line cannot know how long your char[] is, so it just accepts as much input as there is. You must never use char buffers for input you don't know is well-formed. What you're seeing is a buffer overflow in action. Writing over memory that doesn't belong to any variable you allocated results in undefined behaviour, so your program might just work, crash with e.g. a segfault (accessing memory that the OS never gave you), or overwriting existing part's of your processes' memory, or … just do anything, because it's really undefined.
So, you're writing C++, not C. just
string s;
cin >> s;
cout << s.length()
<< endl
<< s;
to avoid dealing with the (very dangerous) C strings.
You're right, it might still echo correctly if you write more than 5 characters. You're simply writing off the end of the buffer, and just blasting the memory that's next to the memory allocated for char s[5]. This is bad for many reasons, including security vulnerabilities. See here for details.
If you can't use string (for whatever reason), use fgets. See here for the documentation on fgets and how it is used. NEVER USE gets. It's almost equivalent to what you've done above, see here for why gets is so dangerous.

How does strcat() work in C++?

I have a difficulty in understanding how strcat works.
char A[] = "H";
char B[] = "L";
char C[] = "12345678901234567890"; // 20 digits => 20 bytes
cout<< &A <<" "<< &B <<" "<< &C <<endl;
strcat(A,C);
cout<< &A <<" "<< &B <<" "<< &C <<endl;
Output is
0x7ffd98b99f80 0x7ffd98b99f90 0x7ffd98b99fa0
0x7ffd98b99f80 0x7ffd98b99f90 0x7ffd98b99fa0
According to my understanding, before running strcat, difference in A's location and B's location is 0x10. This means, they have 16 bytes of space in between. After strcat, A has 20 more characters which means it should occupy 20 bytes more. To accommodate these additional characters, I thought that either A or B is shifted to a new location. But neither happens. Where is A storing all its bytes now? How does strcpy work?
strcat does not allocate new memory for you, it is your job to make sure the destination buffer is big enough. It will simply append to the original string assuming it can.
This is clearly stated in every documentation.
When you use strcat, you are responsible for providing adequate space. If you neglect to do so (as in your example), you write into unreserved space, which is undefined behavior.
What's happening is that you are lucky.
strcat() copies the contents of B to the end of A.
In your case, that appears to be exactly where B already exists. You are lucky that your implementation didn't fail on that alone.
strcat() will never (re)allocate memory for a string -- the memory must already exist and be sufficient for the additional string data. Otherwise you are overwriting other objects in memory -- which may cause disastrous results.

Why does that works in c++ char arrays [duplicate]

This question already has answers here:
No out of bounds error
(7 answers)
Closed 8 years ago.
I have the next code:
char arr[6] = "Hello";
strcpy(arr, "Hello mellow");
cout << strlen(arr) << ", " << arr << endl; // 12, Hello mellow
char arr1[] = "Hello";
strcpy(arr1, "Hello mellow");
cout << strlen(arr1) << ", " << arr1 << endl; // 12, Hello mellow
So, why does that work? Why doesn't it get limited somehow? Whatever I put instead of "Hello mellow", it works and prints it out.
It works because strcpy doesn't check that the destination array is at least as large as the source one. Your code invokes undefined behavior as you call strcpy with invalid arguments, and because the behavior is undefined, anything can happen; In your case, the memory is silently overwritten. Your program could crash as well.
In general, C and C++ don't check for boundaries (unlike other higher-level languages: Java, PHP, Python, Javascript, etc).
This means that if you try to strcopy, say, a 13-bytes string such as "Hello mellow" to a character array, it won't check whether or not the given array has been instantiated with enough memory to contain the string. It will just copy the given string, character by character, to the given memory pointer.
What happens here, is that you write at some places in memory you are not supposed to access; once in a while, this program might just crash, with no other indication than: segmentation fault.
If you happen to try this...
char arr1[8];
char arr2[8];
strcpy(arr1,"Hello mellow");
printf("%s\n", arr1);
printf("%s\n", arr2);
...it is very likely (but not 100% sure, see comments) you would get the following output:
Hello mellow
llow
Why? Because the second char[] would have been overwritten by the data you tried to put in the first one, without it having enough reserved space for it.
See: http://en.wikipedia.org/wiki/Stack_buffer_overflow
Native arrays in C/C++ are very low-level abstractions that are treated as pointers to memory locations in many use cases. So, when passing arr to strcpy, all strcpy knows is the address of arr[0]. As a result, there is no possibility of bounds checking. This is a very good thing for performance reasons. It is up to the programmer to ensure that he/she uses these low-level constructs safely, for instance by using strncpy and giving an appropriate bound, or using std::vector and checking for bounds explicitly or using std::vector::at to check bounds when accessing a location.
I think that's because there's no check runtime nor compile time and if you're Lucky, you won't get a segmentation fault;)