snprintf of unsigned long appending a comma - c++

I try to convert a unsigned long into a character string, appending a comma at the end of the it. When compiling and running the test code you can find below, I get the following output:
"1234," "1234"
"1234"
The test code is:
#include <cstdio>
#include <iostream>
int main () {
unsigned long c = 1234;
char ch[50];
char ch1[50];
sprintf(ch, "%lu,", c);
std::cout << "\"" << ch << "\"" << " \"" << c << "\"" << std::endl;
snprintf(ch1, 5, "%s", ch);
std::cout << "\"" << ch1 << "\"" << std::endl;
return 1;
}
As far as I understand, ch should be of length 5, 4 digits plus 1 for the comma.
Do I miss an extra plus one for the termination character?
Cheers!

The size that is passed to snprintf includes the terminating null character. Although it is not printed, it still takes space in the buffer.
You should pass strlen(ch) + 1 instead. Or even better, just sizeof(ch1) will suffice since you want to accommodate the entire result before filling the buffer.
Also make sure that the destination buffer is always of a sufficient size, equal to or greater than the size you pass to snprintf. In your particular case it can hardly happen, but in general you should keep that in mind.

From the Linux manual page:
The functions snprintf() and vsnprintf() write at most size bytes (including the trailing null byte ('\0')) to str.
So yes, you should have a length of 6 to get the comma as well.

The C++ way:
#include <string>
unsigned long int c = 1234;
std::string s = "\"" + std::to_string(c) + ",\"";
std::string t = '"' + std::to_string(c) + ',' + '"'; // alternative

As you wrote, you miss an extra space for the termination character.
The functions snprintf() and vsnprintf() write at most size bytes
(including the terminating null byte ('\0')) to str.

As several people has pointed out, you need to include enough space for the null terminator.
It's always worth checking the result returned from snprintf is what you think it should be, as well.
Lastly, I'd recommend using snprintf(buffer, sizeof(buffer), etc, etc)
Your less likely to get embarrassing results if the 2nd parameter happens to be larger than the actual space you've got available.

Related

Strcat not appending a character

char* oledScreen::getCurrentTime(){
char* hour = malloc(16);
snprintf(hour, 16, "%d", getHour());
char* minute = malloc(16);
snprintf(minute, 16, "%d", getMinute());
char* firstPart = strcat(getHour() < 10 ? strcat("0",hour) : hour, ":");
const char* secondPart = getMinute() < 10 ? strcat("0",minute) : minute;
return strcat(firstPart, secondPart);
};
I'm trying to append two integers, which I can obtain using getHour() and getMinute(). However, I need to check if one of these two are less than 10: if so, I need to append a 0 so that the output is such that: 0X, where X is getHour() or getMinute().
My problem is that it does not append the : character. For instance, if getHour() = 9 and getMinute() = 15. The output of getCurrentTime() is 0915 and not 09:15. Do you have any idea why this is like this?
To begin with, strcat("0",hour) will lead to undefined behavior as you attempt to modify the literal string "0" which isn't allowed.
Instead of using multiple strcat calls, why not simply create a string large enough to fit the result, and use snprintf to put contents into the string?
Using snprintf will also make it easier to optionally add a zero-prefix to the hour value.
Perhaps something like this:
// Allocate memory, and actually create the string
// 2 for hour, 2 for minutes, 1 for colon, 1 for terminator
char *result = malloc(6);
snprintf(result, 6, "%02d:%02d", getHour(), getMinute());
return result;
As mentioned in comments, a better solution would be to pass in the result array as an argument to the function. The would handle ownership of the result array better, and might not even need dynamic allocation.
[Note that the above is a pure C solution, it's not even valid in C++. I wrote it before noticing that the code in the question is really C++.]
Considering that you really seem to be programming in C++, not C, then a solution using string streams and std::string would be more appropriate:
std::string oledScreen::getCurrentTime(){
std::ostringstream oss;
oss << std::setw(2) << std::setfill('0') << getHour() << ':'
<< std::setw(2) << std::setfill('0') << getMinute();
return oss.str();
}

Are std::string with null-character possible?

I initialized a C++ string with a string literal and replaced a char with NULL.
When printed with cout << the full string is printed and the NULL char prints as blank.
When printed as c_str the string print stop at the NULL char as expected.
I'm a little confused. Does the action came from cout? or string?
int main(){
std::string a("ab0cd");
a[2] = '\0'; // '\0' is null char
std::cout << a << std::endl; // abcd
std::cout << a.c_str() << std::endl; // ab
}
Test it online.
I'm not sure whether the environment is related, anyway, I work with VSCode in Windows 10
First you can narrow down your program to the following:
#include <iostream>
#include <string>
int main(){
std::string a("ab0cd");
a[2] = '\0'; // replace '0' with '\0' (same result as NULL, just cleaner)
std::cout << a << "->" << a.c_str();
}
This prints
abcd->ab
That's because the length of a std::string is known. So it will print all of it's characters and not stop when encountering the null-character. The null-character '\0' (which is equivalent to the value of NULL [both have a value of 0, with different types]), is not printable, so you see only 4 characters. (But this depends on the terminal you use, some might print a placeholder instead)
A const char* represents (usually) a null-terminated string. So when printing a const char* it's length is not known and characters are printed until a null-character is encountered.
Contrary to what you seem to think, C++ string are not null terminated.
The difference in behavior came from the << operator overloads.
This code:
cout << a.c_str(); // a.c_str() is char*
As explained here, use the << overloads that came with cout, it print a char array C style and stop at the first null char. (the char array should be null terminated).
This code:
cout << a; // a is string
As explained here, use the << overloads that came with string, it print a string object that internally known is length and accept null char.
string end limit (boundary) is not 0 (NULL) like simple char* but its size keep internally in its member data as it's actually user-defined type (an instantiated object) as opposed to primitive type, so
int main(){
string a("abc0d");
a[3] = 0; // '\0' is null char
a.resize(2);
std::cout << a << std::endl; // ab
std::cout << a.c_str() << std::endl; // ab
}
i'm sorry change your code to be more comfortable, watch as it results in
ab
ab
good learning: http://www.cplusplus.com/reference/string/string/find/index.html

Storing data in char array causing corruption around variable

I am working on a C++ project and I am having an issue.
Below is my code
tempfingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_TYPE_RSA);
char temp[48];
memset(temp, 0, sizeof(temp));
for (i = 0; i < 16; i++)
{
//fingerprintstream << (unsigned char)tempfingerprint[i] << ":";
if (temp[0] == 0)
{
sprintf(temp, "%02X:", (unsigned char)tempfingerprint[i]);
}
else
{
//sprintf(temp, "%s:%02X", temp, (unsigned char)tempfingerprint[i]);
char characters[3];
memset(characters, 0, sizeof(characters));
//If less than 16, then add the colon (:) to the end otherwise don't bother as we're at the end of the fingerprint
sprintf(characters, "%02X:", (unsigned char)tempfingerprint[i]);
strcat(temp, characters);
}
}
//Remove the end colon as its not needed. 48 Will already be null terminated, so the previous will contain the last colon
temp[47] = 0;
return string(temp);
When I run my app, I get the following error from visual studio
Run-Time-Check Failure #2 - Stack around the variable 'temp' was corrupted.
I've ran the same code on Linux through Valgrind and no errors were shown so I'm not sure what the problem is with Windows.
Here's an approach using on what Paul McKenzie's talking about (though he might implement it differently) based on it looks like you were trying to do with the stream
#include <iostream>
#include <sstream>
#include <iomanip> // output format modifiers
using namespace std;
int main()
{
stringstream fingerprintstream;
// set up the stream to print uppercase hex with 0 padding if required
fingerprintstream << hex << uppercase << setfill('0');
// print out the first value without a ':'
fingerprintstream << setw(2) << 0;
for (int i = 1; i < 16; i++) // starting at 1 because first has already been handled.
{
// print out the rest prepending the ':'
fingerprintstream << ":" << setw(2) << i;
}
// print results
std::cout << fingerprintstream.str();
return 0;
}
Output:
00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F
Just realized what I think OP ran up against with the garbage output. When you output a number, << will use the appropriate conversion to get text, but if you output a character << prints the character. So fingerprintstream << (unsigned char)tempfingerprint[i]; takes the binary value at tempfingerprint[i] and, thanks to the cast, tries to render it as a character. Rather than "97", you will get (assuming ASCII) "a". A large amount of what you try to print will give nonsense characters.
Example: If I change
fingerprintstream << ":" << setw(2) << i;
to
fingerprintstream << ":" << setw(2) << (unsigned char)i;
the output becomes
0?:0?:0?:0?:0?:0?:0?:0?:0?:0?:0 :0
:0?:0?:0
:0?:0?
Note the tab and the line feeds.
I need to know the definition of tempfingerprint to be sure, but you can probably solve the garbage output problem by removing the cast.
Based on new information, tempfingerprint is const char *, so tempfingerprint[i] is a char and will be printed as a character.
We want a number, so we have to force the sucker to be an integer.
static_cast<unsigned int>(tempfingerprint[i]&0xFF)
the &0xFF masks out everything but the last byte, eliminating sign extension of negative numbers into huge positive numbers when displayed unsigned.
There are, as far as I see, two issues in the code which lead to exceeding array boundaries:
First, with char temp[48] you reserve exactly 48 characters for storing results; However, when calling strcat(temp, characters) with the 16th value, and characters comprises at least the characters including the colon, then temp will comprise 16*3 digits/colons + one terminating '\0'-character, i.e. 49 characters (not 48). Note that strcat automatically appends a string terminating char.
Second, you define char characters[3] such that you reserve place for two digits and the colon, but not for the terminating '\0'-character. Hence, an sprintf(characters, "%02X:",...) will exceed characterss array bounds, as sprintf also appends the string terminator.
So, if you do not want to rewrite your code in general, changing your definitions to char temp[49] and char characters[4] will solve the problem.

Read into std::string using scanf

As the title said, I'm curious if there is a way to read a C++ string with scanf.
I know that I can read each char and insert it in the deserved string, but I'd want something like:
string a;
scanf("%SOMETHING", &a);
gets() also doesn't work.
Thanks in advance!
this can work
char tmp[101];
scanf("%100s", tmp);
string a = tmp;
There is no situation under which gets() is to be used! It is always wrong to use gets() and it is removed from C11 and being removed from C++14.
scanf() doens't support any C++ classes. However, you can store the result from scanf() into a std::string:
Editor's note: The following code is wrong, as explained in the comments. See the answers by Patato, tom, and Daniel Trugman for correct approaches.
std::string str(100, ' ');
if (1 == scanf("%*s", &str[0], str.size())) {
// ...
}
I'm not entirely sure about the way to specify that buffer length in scanf() and in which order the parameters go (there is a chance that the parameters &str[0] and str.size() need to be reversed and I may be missing a . in the format string). Note that the resulting std::string will contain a terminating null character and it won't have changed its size.
Of course, I would just use if (std::cin >> str) { ... } but that's a different question.
Problem explained:
You CAN populate the underlying buffer of an std::string using scanf, but(!) the managed std::string object will NOT be aware of the change.
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.reserve(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: '" << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: (size = 0)
Underlying buffer: Daniel (size = 6)
So, what happened here?
The object std::string is not aware of changes not performed through the exported, official, API.
When we write to the object through the underlying buffer, the data changes, but the string object is not aware of that.
If we were to replace the original call: token.reseve(64) with token.resize(64), a call that changes the size of the managed string, the results would've been different:
const char *line="Daniel 1337"; // The line we're gonna parse
std::string token;
token.resize(64); // You should always make sure the buffer is big enough
sscanf(line, "%s %*u", token.data());
std::cout << "Managed string: " << token
<< " (size = " << token.size() << ")" << std::endl;
std::cout << "Underlying buffer: " << token.data()
<< " (size = " << strlen(token.data()) << ")" << std::endl;
Outputs:
Managed string: Daniel (size = 64)
Underlying buffer: Daniel (size = 6)
Once again, the result is sub-optimal. The output is correct, but the size isn't.
Solution:
If you really want to make do this, follow these steps:
Call resize to make sure your buffer is big enough. Use a #define for the maximal length (see step 2 to understand why):
std::string buffer;
buffer.resize(MAX_TOKEN_LENGTH);
Use scanf while limiting the size of the scanned string using "width modifiers" and check the return value (return value is the number of tokens scanned):
#define XSTR(__x) STR(__x)
#define STR(__x) #x
...
int rv = scanf("%" XSTR(MAX_TOKEN_LENGTH) "s", &buffer[0]);
Reset the managed string size to the actual size in a safe manner:
buffer.resize(strnlen(buffer.data(), MAX_TOKEN_LENGTH));
The below snippet works
string s(100, '\0');
scanf("%s", s.c_str());
Here a version without limit of length (in case of the length of the input is unknown).
std::string read_string() {
std::string s; unsigned int uc; int c;
// ASCII code of space is 32, and all code less or equal than 32 are invisible.
// For EOF, a negative, will be large than 32 after unsigned conversion
while ((uc = (unsigned int)getchar()) <= 32u);
if (uc < 256u) s.push_back((char)uc);
while ((c = getchar()) > 32) s.push_back((char)c);
return s;
}
For performance consideration, getchar is definitely faster than scanf, and std::string::reserve could pre-allocate buffers to prevent frequent reallocation.
You can construct an std::string of an appropriate size and read into its underlying character storage:
std::string str(100, ' ');
scanf("%100s", &str[0]);
str.resize(strlen(str.c_str()));
The call to str.resize() is critical, otherwise the length of the std::string object will not be updated. Thanks to Daniel Trugman for pointing this out.
(There is no off-by-one error with the size reserved for the string versus the width passed to scanf, because since C++11 it is guaranteed that the character data of std::string is followed by a null terminator so there is room for size+1 characters.)
int n=15; // you are going to scan no more than n symbols
std::string str(n+1); //you can't scan more than string contains minus 1
scanf("%s",str.begin()); // scanf only changes content of string like it's array
str=str.c_str() //make string normal, you'll have lots of problems without this string

What's wrong with my memcpy?

I have written a function to implement memcpy
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
char *memcpy(char *dest,char *src,int n){
char *ch=dest;
while (n--)
*ch++=*src++;
return dest;
}
int main(){
char *src="georgia";
int n=strlen(src);
char *dest=new char[n];
std::cout<<*memcpy(dest,src,n)<<std::endl;
return 0;
}
But it only prints a single g. Why?
Because you're printing a single character.
std::cout<<*memcpy(dest,src,n)<<std::endl;
This dereferences the destination buffer (*memcpy) and therefore returns the first character of the string (which is g). You should be fine using this:
std::cout << memcpy(dest, src, n) << std::endl;
Other than that, it's still not gonna work: you need to include the terminating NULL character of your string in the copy, but strlen excludes it from the length of the string; so your buffer is missing 1 character. You need to add 1 to n to balance it, and everything should be fine.
int n = strlen(src) + 1;
Nothing wrong with the memcpy function but you have the * operation on the result. If we break the print line down it is...
char * result = memcpy(dest,src,n);
std::cout << *result << std::endl;
You really want...
std::cout << memcpy(dest,src,n) << std::endl;
Your memcpy() returns a pointer to char. In the line
std::cout<<*memcpy(dest,src,n)<<std::endl;
you dereference the pointer (you use operator*) so effectively you send one char (the one the return value points to) to the stream.
There is a bug in your code. strlen returns number of characters in the literal "georgia", but wihtout the terminating null character. You should increase n by one, to allocate appropriate storage for dest and to copy also the terminating null character.
You're dereferencing a char*, which is a char. This will be the first character, g.