I know the size of destination is small so that my code not working correctly but all I want to know when I put 35 in destination character print in infinite loop why it become infinite only when I put 35 in other number it crash or work in bigger number.
I am using Windows 7 Code Block with gcc.
using namespace std;
int main()
{
char dest[35] = "This is an example";//when put another number it work or crash but at this number it print infinite number of character why what is logic
char src[50] = " to show working of strncat() this is not added";
strncat(dest, src, 29);
cout << dest ;
return 0;
}
You have 17 characters plus a null byte in the initialized dest array.
When you call strncat(dest, src, 29), you say "it is safe to add 29 extra characters to dest" — which is nonsense as you can only add 17 characters without overflowing the array.
You invoked undefined behaviour. That means the program can work, or crash, or go into an infinite loop, and all those behaviours are OK because undefined behaviour doesn't have to behave in any specific way.
Note that strncat(dst, sizeof(dst), very_long_string) is a boundary error, even if dst[0] == '\0'. You can use strncat(dst, sizeof(dst)-1, very_long_string) if the destination is empty. (The very long string is any string longer than sizeof(dst) - 1, of course.)
Related
You can see the parameter sent to the function does not exceed the buffer size from the code below.
This problem happened randomly, and only happened in debug build.
#include <thread>
#include <sstream>
#define BUF_SZ 32
int main()
{
wchar_t src[BUF_SZ]{};
bool running = true;
std::thread th([&] {
for (double g = 0; g < 100000; g += .1)
{
std::wstringstream ws;
ws << g;
wcscpy_s(src, BUF_SZ, ws.str().c_str());
}
running = false;
});
wchar_t dst[BUF_SZ]{};
while (running)
wcscpy_s(dst, src); // assert on "Buffer is too small" randomly
th.join();
return 0;
}
Thanks to Mr. Steve Wishnousky from MSFT VC++ team, here is the complete explanation of the problem.
Wcscpy_s does not operate atomically on the buffers and will only work
correctly if the buffers do not change contents during the runtime of
wcscpy_s.
Another thing to note is that in Debug mode, the wcscpy_s function
will fill the rest of the buffer in with a debug mark (0xFE) to
indicate that the data there is now invalid to assume it's contents,
in order to detect potential runtime errors.
The error happens differently every time of course, but lets assume
this error happens when src=1269.9 and wcscpy_s(dst, src) is called.
The actual contents of src is: "1 2 6 9 . 9 null 0xfe 0xfe ...".
wcscpy_s copies over the 1269.9 but as it's about to read the null,
the other wcscpy_s just wrote a new value to src so it's now: "1 2 7 0
null 0xfe 0xfe ...". Instead of reading the null corresponding from
the previous src, it reads the 0xfe, so it thinks this is a real
character. Since there is no null terminator until we reach the end of
the buffer, the Debug runtime asserts that the buffer was too small
for the input.
In the Release build, the 0xFE debug marks aren't placed in the
buffer, so it will eventually find a null character. You can also
disable the debug marks by calling _CrtSetDebugFillThreshold:
https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/crtsetdebugfillthreshold?view=vs-2019.
Note that the Debug marks are actually catching a real correctness
problem here though. This "buffer changed during wcscpy_s" issue could
happen for any value. For example, if src=1269.9, wcscpy_s could copy
over the 126, but then as it's about to read the 9, src is updated to
1270 and the value that would end up in dest would be "1260".
Since the string copy will need to copy "src" characters and a terminating null character you'll need to provide a buffer which is at least one character bigger than sizeof "src".
I suggest you could try to use:
wcscpy_s(dst, sizeof src+1, src);
In my code, I've been trying to find the length of a specific string in a string array. However, when I do it, no matter what method I try to find the length of the specific string, always returns -858993460
The code I've been working with is
void drawChoices(int x, std::string s [], int iChoice)
{
setCurPos(x, 1); //this function just sets the console cursor
for (int i = 0; i <= iChoice; i++)
{
color(15, 4); //this function just sets the console color
std::cout << "[" << s[i] << "]";
color(8, 8);
int asfa = sizeof s[i]; //this is the one causing trouble
std::cout << " \n";
}
}
I tried finding the length of the string in the array with sizeof, string::length, and strlen, but those yielded the same results.
You can never obtain the length of a string with sizeof. The sizeof operator is evaluated at compile time and returns the size of a type or variable. Your use of sizeof is:
sizeof s[i]
Since s[i] has type std::string, that expression evaluates to whatever size your implementation's std::string happens to be. But that is determined at compile time, and so has no dependency on the contents of the buffer, and is something that you are simply not interested in knowing.
Use either std::string::size() or std::string::length() to obtain the length of a std::string.
So, in your code you would use
s[i].length()
to obtain the length, that is the number of character elements, in the string s[i]. Do note also that the size() and length() methods, which are interchangeable, return std::string::size_type which you should use rather than int.
As for where the negative value comes from, we cannot say. Your code doesn't output the value that sizeof yielded, which would not be negative in any case.
Should your loop really be
for (int i = 0; i <= iChoice; i++)
rather than
for (int i = 0; i < iChoice; i++)
Rather than passing, and presumably storing, arrays of std::string, it would be more idiomatic to use a C++ container. In this case std::vector<std::string>.
From what #VladfromMoscow mentioned, I have figured out the problem.
The problem was when I was using Visual Studio 2013's debugging and local windows, I was debugging the same time the variable was initializing.
With the local window compiling the order of the line and how Visual Studio's debugging works, it gives out a random number because the variable wasn't initialized.
It reads size_t asfa first, stops it, local window gets the value, and then executes s[i].length(); once I continue it.
I thought it would be the program's fault because I tried outputting std::cout << asfa;, but I remebered that you can't have an int or size_t to a string directly, without a cast or conversion. Thank you for all of you who helped.
#include<iostream>
#include<string.h>
#include<stdio.h>
int main()
{
char left[4];
for(int i=0; i<4; i++)
{
left[i]='0';
}
char str[10];
gets(str);
strcat(left,str);
puts(left);
return 0;
}
for any input it should concatenate 0000 with that string, but on one pc it's showing a diamond sign between "0000" and the input string...!
You append a possible nine (or more, gets have no bounds checking) character string to a three character string (which contains four character and no string terminator). No string termination at all. So when you print using puts it will continue to print until it finds a string termination character, which may be anywhere in memory. This is, in short, a school-book example of buffer overflow, and buffer overflows usually leads to undefined behavior which is what you're seeing.
In C and C++ all C-style strings must be terminated. They are terminated by a special character: '\0' (or plain ASCII zero). You also need to provide enough space for destination string in your strcat call.
Proper, working program:
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(void)
{
/* Size is 4 + 10 + 1, the last +1 for the string terminator */
char left[15] = "0000";
/* The initialization above sets the four first characters to '0'
* and properly terminates it by adding the (invisible) '\0' terminator
* which is included in the literal string.
*/
/* Space for ten characters, plus terminator */
char str[11];
/* Read string from user, with bounds-checking.
* Also check that something was truly read, as `fgets` returns
* `NULL` on error or other failure to read.
*/
if (fgets(str, sizeof(str), stdin) == NULL)
{
/* There might be an error */
if (ferror(stdin))
printf("Error reading input: %s\n", strerror(errno));
return 1;
}
/* Unfortunately `fgets` may leave the newline in the input string
* so we have to remove it.
* This is done by changing the newline to the string terminator.
*
* First check that the newline really is there though. This is done
* by first making sure there is something in the string (using `strlen`)
* and then to check if the last character is a newline. The use of `-1`
* is because strings like arrays starts their indexing at zero.
*/
if (strlen(str) > 0 && str[strlen(str) - 1] == '\n')
str[strlen(str) - 1] = '\0';
/* Here we know that `left` is currently four characters, and that `str`
* is at most ten characters (not including zero terminaton). Since the
* total length allocated for `left` is 15, we know that there is enough
* space in `left` to have `str` added to it.
*/
strcat(left, str);
/* Print the string */
printf("%s\n", left);
return 0;
}
There are two problems in the code.
First, left is not nul-terminated, so strcat will end up looking beyond the end of the array for the appropriate place to append characters. Put a '\0' at the end of the array.
Second, left is not large enough to hold the result of the call to strcat. There has to be enough room for the resulting string, including the nul terminator. So the size of left should at least 4 + 9, to allow for the three characters (plus nul terminator) that left starts out with, and 9 characters coming from str (assuming that gets hasn't caused an overflow).
Each of these errors results in undefined behavior, which accounts for the different results on different platforms.
I do not know why you are bothering to include <iostream> as you aren't using any C++ features in your code. Your entire program would be much shorter if you had:
#include <iostream>
#include <string>
int main()
{
std::string line;
std::cin >> line;
std::cout << "You entered: " << line;
return 0;
}
Since std::string is going to be null-terminated, there is no reason to force it to be 4-null-terminated.
Problem #1 - not a legal string:
char left[4];
for(int i=0; i<4; i++)
{
left[i]='0';
}
String must end with a zero char, '\0' not '0'.
This causes what you describe.
Problem #2 - fgets. You use it on a small buffer. Very dangerous.
Problem #3 - strcat. Yet again trying to fill a super small buffer which should have already been full with an extra string.
This code looks an invitation to a buffer overflow attack.
In C what we call a string is a null terminated character array.All the functions in the string.h library are based on this null at the end of the character array.Your character array is not null terminated and thus is not a string , So you can not use the string library function strcat here.
I'm trying to understand un-managed code. I come from a background of C# and I'm playing around a little with C++.
Why is that this code:
#include <iostream>
using namespace std;
int main()
{
char s[] = "sizeme";
cout << sizeof(s);
int i = 0;
while(i<sizeof(s))
{
cout<<"\nindex "<<i<<":"<<s[i];
i++;
}
return 0;
}
prints out this:
7
index 0:s
index 1:i
index 2:z
index 3:e
index 4:m
index 5:e
index 6:
????
Shouldn't sizeof() return 6?
C strings are "nul-terminated" which means there is an additional byte with value 0x00 at the end. When you call sizeof(s), you are getting the size of the entire buffer including the nul terminator. When you call strlen(s), you are getting the length of the string contained in the buffer, not including the nul.
Note that if you modify the contents of s and put a nul terminator somewhere other than at the end, then sizeof(s) would still be 7 (because that's a static property of how s is declared) but strlen(s) could be somewhat less (because that's calculated at runtime).
No, all trings in C are terminated by the null character (ascii 0). So s is actually 7 bytes
s i z e m e \0
This is due to the fact, that C-strings contain the value 0 (or '\0') as last character to mark the end of the string.
s is seven bytes, 6 for the string and one for the null termination.
Can anyone spot the reason why nothing gets printed onto console using below C++ code;
string array[] = { "a", "b", "c", "d" };
int length = sizeof(array);
try
{
for (int i = 0; i < length; i++)
{
if (array[i] != "") cout << array[i];
}
}
catch (exception &e)
{
e.what();
}
You use the wrong length:
int length = sizeof(array)/sizeof(array[0])
The actual reason you don't see anything on the console is because the output is buffered, and since you haven't wrote a newline it's not flushed. In the meantime your app crashes.
No end of line character.
Also as mentioned by Dave, sizeof is not the length of the array
This answer assumes that string == std::string.
let T be an arbitrary type, and n be an arbitrary positive integer - then:
sizeof(T[n]) == n * sizeof(T)
That is - sizeof(array) is not the length of the array, but the total amount of memory used by the array (in chars). Your std::string implementation could very well be using more than 1 char's worth of memory to store its structure. This leads to length holding a value much greater than 4.
This causes the program to read from past the end of array; an operation for which C++ imposes no requirements (it is Undefined Behaviour).
In terms of the C++ abstract machine, a program containing Undefined Behaviour can do absolutely anything, even before the point in the execution of the program at which the Undefined Behaviour was encountered. In your particular case your program exhibits this behaviour by not printing anything (even though you had made 4 well defined calls to operator<< before the erroneous array indexing).
You have tagged this eclipse-cdt, so I will assume that you are using GCC to compile your program, and are running it under a modern operating system with memory-protection. In this case the actual reason for the behaviour that you are seeing is probably that std::cout is buffering the first few strings that you stream into it and so not immediately printing them to the console. After that you get to the buffer overrun and your operating system interrupts the process with a EXC_BAD_ACCESS signal or similar. This causes the immediate termination of your program, which does not give std::cout a chance to flush its buffered values. All up, this means that nothing gets printed.
As mentioned in another answer, you should replace the line:
length = sizeof(array);
with:
length = sizeof(array)/sizeof(array[0]);
This will guarantee that length will hold the value 4, rather than the value 4 * sizeof(string), that could be many times the length of the array.