C++ concatenate two unsigned char* [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have two unsigned char* and trying two concatenate. Here is the sample of code.
unsigned char* finaleResult = (unsigned char*)malloc(size);
memcpy(finaleResult, part1, sizeof(part1));
memcpy(finaleResult+sizeof(part1), part2, sizeof(part2));
finaleResult[sizeof(part1) + sizeof(part2)+1] = '\0';
std::cout << "finaleResult: " << finaleResult << std::endl;
I assume to see two part1 + part2 in the finaleResult but there is only part1.
What is wrong with my code?

If you're using C++, there is no need to do any manual memory management for string-like data and doing manipulations such as concatenation.
The std::basic_string template provides functions that do the concatenation for you. All you have to do is supply the type as a template argument to std::basic_string.
Since the type is unsigned char, using std::basic_string<unsigned char> gives you concatenation right out-of-the-box:
#include <string>
#include <iostream>
int main()
{
std::basic_string<unsigned char> part1 = {'a','b','c'};
std::basic_string<unsigned char> part2 = {'1','2','3'};
std::basic_string<unsigned char> finaleResult = part1 + part2; // magic
std::cout << finaleResult.c_str();
}
Output:
abc123

There are many issues with this code.
unsigned char * is not meant to point at a C string. If you are working with strings in C, you are expected to use plain char *. unsigned char * is generally considered to be pointing at raw data.
Strings
In C, you would use strcpy and strcat to copy / concatenate strings, respectively. Make sure your destination has enough memory malloc'ed to contain the concatenated string, plus the null terminator.
In C++, you do none of the above. No malloc, no memcpy or strcpy or strcat, and no pointers. You #include <string> and use the std::string class.
std::string finaleResult{ part1 };
finaleResult += part2;
std::cout << "finaleResult: " << finaleResult << std::endl;
Data
Later on you confirmed in comments that you are, indeed, handling raw data here. We don't really see what part1 and part2 and size are, so there's some guesswork involved, but I assume that somewhere in part1, in the very least at finalResult[ sizeof( part1 ) ], you got a zero byte, which makes std::cout stop the output.
Similar as with strings (see above), in C++ you should not work with C primitives (arrays, malloc, owning pointers) when handling raw data.
If you have to use dynamic memory allocation, use std::unique_ptr to get a smart pointer that releases the memory upon destruction (e.g. in case of an exception being thrown).
But generally, you will fare better with <vector>, which relieves you from the burden of managing any resources by hand:
vector< unsigned char > finaleResult { part1, part1 + sizeof part1 };
finaleResult.insert( result.end(), part2, part2 + sizeof part2 );
To avoid funny business with embedded zero bytes, characters outside ASCII-7 range, and generally data that isn't supposed to be interpreted as string, use hex output:
int elements { 0 };
int const elements_per_line { 4 };
for ( auto && c : finaleResult )
{
std::cout << std::hex << std::setfill( '0' ) << std::setw( 2 ) << static_cast< int >( c ) << " ";
if ( ( ++elements % elements_per_line ) == 0 )
{
std::cout << std::endl;
elements = 0;
}
}

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();
}

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

The sizeof several casts

Why does the function sizeof not return the same size when its getting used on the struct itself?
I need to cast it because of a winsock program that im working on.
Thanks for any help, true.
#include <iostream>
#include <string>
using namespace std;
struct stringstruct
{
string s1;
string s2;
};
int main()
{
stringstruct ss = {"123","abc"};
char *NX = (char*)&ss;
cout << sizeof(NX) << endl << sizeof(*NX) << endl;
cout << sizeof(&ss) << endl << sizeof(ss) << endl;
getchar();
return 0;
}
the example above outputs
4
1
4
64
sizeof will tell you the size of the given expression's type. In both the sizeof(NX) and sizeof(&ss), the result is 4 because pointers on your machine take up 4 bytes. For sizeof(*NX), you are dereferencing a char*, which gives you a char, and a char takes up 1 byte (and always does), so you get the output 1. When you do sizeof(ss), ss is a stringstruct, so you get the size of a stringstruct, which appears to be 64 bytes.
stringstruct ss = {"123","abc"};
char *NX = (char*)&ss;
cout << sizeof(NX) << endl << sizeof(*NX) << endl;
cout << sizeof(&ss) << endl << sizeof(ss) << endl;
I'm pretty sure that any of these casts are pretty meaningless. NX will point at the beginning of your struct. Inside the struct are two objects of type string, which in turn have pointers pointing to the data they were initialized with "123" and "abc" respectively. sizeof(*NX) is just that - size of a char, and sizeof(NX) is indeed the size of a pointer. sizeof(ss) is the size of your two string members (and any padding added by the compiler) - and sizeof(&ss) is the size of a pointer to a stringstruct.
Now, I expect what you REALLY want is a way to send your data, "123" and "abc" as two separate strings over a network. None of the above will help you do that, since even if sizeof(ss) gives you the size of the data structure you want to send, the string values are not within that structure [1]. What you really need is something calls serialization - something that writes out your strings as separate elements as text/string.
Something like this would work:
struct stringstruct {
string s1;
string s2;
string to_string()
}
string stringstruct::to_string()
{
string res = s1 + " " + s2;
return res;
}
Then use to_string like this:
string temp = ss.to_string();
const char *to_send = temp.c_str();
int send_len = temp.length();
... send the string `to_send` with number of bytes `send_len`.
[1] There is an optimization where std::string is actually storing short strings within the actual class itself. But given a sufficiently long strong, it won't do that.
A pointer is of size 4(in your case seems to be 32 bit) no matter what it points. Size of the object itself on the other hand returns the real number of bytes that an object of that structure takes.

Infinity value and buffer

i have a score board that get update all time with new information and the buffer size is = amount of rows my
score board can handel, but i'm trying to make it infinity without limits.
what i'm trying to do is as-sign infinity value to a buffer like that:
const int infinity = std::numeric_limits<const int>::infinity();
char Buffer_format_text [infinity];
but it dont work, becouse it says:
error C2057: expected constant expression
error C2466: cannot allocate an array of constant size 0
is there a way to do that? or trick? , please help me. Don't ask me why i want to do that, i'm asking how to do that.
Update:
This how i'm doing it with sprintf , how do you that in ostringstream ?
char Buff[100];
int length = 0;
int amount_of_space = 8;
length += sprintf(Buff+length,"%-*s %s\n", amount_of_space, "Test", "Hello");
this output: Test Hello
In C++11, infinity() is constexpr, so in theory you could use it directly this way:
char Buffer_format_text[std::numeric_limits<const int>::infinity()];
However, the problem here is that int cannot represent infinity. If you tried this:
std::cout << std::numeric_limits<const int>::has_infinity;
You would see that 0 (false) is printed to the standard output (live example). The infinity() function for specializations of std::numeric_limits where has_infinity is false will return 0 - in fact, the function is meaningless in those cases - and you cannot create arrays of size 0.
Besides, you cannot expect an array of infinite size to be allocated - how would it fit into memory? The right approach, if you do not know in advance the size of your vector, is to use std::vector or a similar container that does allocate memory upon request.
UPDATE:
It seems what you actually need an infinite array for is to be able to build up a string whose size is not known in advance. To encapsulate such a string that grows dynamically, you can use std::string.
In order to perform type-safe output into an std::string and replace sprintf(), you could use std::ostringstream. That would allow you to insert stuff into a string the same way you would print it to the standard output.
Then, once you are done working with the std::ostringstream, you can get an std::string object from it by calling the str() member function.
This is how you could use it in a simple example:
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
int main()
{
std::ostringstream oss;
oss << "The answer is: ";
oss << 42;
oss << ", and this is a double: ";
oss << 3.14;
oss << ". " << std::endl;
oss << "Oh, btw, you can also output booleans: ";
oss << std::boolalpha << true;
oss << ". See? It's easy!" << std::endl;
std::cout << oss.str();
}
Live demo.
It doesn't make sense to declare a buffer as big as infinity, both because integral types cannot (normally) represent infinity (the infinity member of numeric_limits is there for FP types), and because no machine could create a buffer infinity bytes big. :)
Instead, use a container that can handle the reallocations needed for new insertions by itself, limited only by the available memory, e.g. std::vector (or std::deque or others, depending from your insertion/removal patterns).
Edit: since the question seem to be about creating an arbitrarily long string, the "C++ answer" is to use std::ostringstream, which allow you to write as many elements as you like (limited only by the available memory) and provides you a std::string as a result.
std::ostringstream os;
for(int i=0; i<1000; i++)
os<<rand()<<" ";
std::string out=os.str();
// now in out you have a concatenation of 1000 random numbers
Edit/2:
This how i'm doing it with sprintf , how do you that in ostringstream ?
char Buff[100];
int length = 0;
int amount_of_space = 8;
length += sprintf(Buff+length,"%-*s %s\n", amount_of_space, "Test", "Hello");
// needed headers: <sstream> and <iomanip>
std::ostringstream os;
int amount_of_space = 8;
os<<std::left<<std::setw(amount_of_space)<<"Test"<<" "<<"Hello";
std::string out=os.str(); // you can get `length` with `out.size()`.
But if you need to do multiple insertions call os.str() only at the end, when you actually need the string. Again, no need to keep track of length, the stream does it automatically.
You basically cannot allocate an array with really infinite memory, either on stack or on the heap.
You also cannot allocate array with size 0 since it is illegal according to the standard.
You may try to use std::vector which grows when necessary by itself. but you still cannot have infinite memory to allocate since your disk space is limited no matter how large it is.
You should use a container which can grow dynamically, such as std::vector (or, as your case seems to be text, std::string).
You can use std::ostringstream to construct a std::string like this:
#include <iomanip>
#include <sstream>
std::ostringstream ss;
ss << std::setw(amount_of_space) << std::left << "Test" << ' ' << "Hello" << '\n';
std::string result = ss.str();

snprintf of unsigned long appending a comma

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.