C++ Static Array Initialization - Memory Issue - c++

I have a header file which contains a member variable declaration of a static char array:
class ABC
{
public:
static char newArray[4];
// other variables / functions
private:
void setArray(int i, char * ptr);
}
In the CPP file, I have the array initialized to NULL:
char ABC::newArray[4] = {0};
In the ABC constructor, I need to overwrite this value with a value constructed at runtime, such as the encoding of an integer:
ABC::ABC()
{
int i; //some int value defined at runtime
memset(newArray, 0, 4); // not sure if this is necessary
setArray(i,newArray);
}
...
void setArray(int i, char * value)
{
// encoding i to set value[0] ... value [3]
}
When I return from this function, and print the modified newArray value, it prints out many more characters than the 4 specified in the array declaration.
Any ideas why this is the case.
I just want to set the char array to 4 characters and nothing further.
Thanks...

How are you printing it? In C++ (and C), strings are terminated with a nul. (\0). If you're doing something like:
char arr[4] = {'u', 'h', 'o', 'h'};
std::cout << arr;
It's going to print "uhoh" along with anything else it runs across until it gets to a \0. You might want to do something like:
for (unsigned i = 0; i < 4; ++i)
std::cout << arr[i];
(Having a static tied to instances of a class doesn't really make sense, by the way. Also, you can just do = {}, though it's not needed since static variables are zero-initialized anyway. Lastly, no it doesn't make sense to memset something then rewrite the contents anyway.)

cout.write(arr, count_of(arr))
If count_of isn't defined in a system header:
template<typename T, size_t N>
inline size_t count_of(T (&array)[N]) { return N; }

Are you printing it using something like
printf("%s", newArray); //or:
cout << newArray;
? If so, you need to leave space for the nul-terminator at the end of the string. C strings are just arrays of characters, so there's no indication of the length of the string; standard library functions that deal with strings expect them to end in a nul (0) character to mark the ending, so they'll keep reading from memory until they find one. If your string needs to hold 4 characters, it needs to be 5 bytes wide so you can store the \0 in the fifth byte

You'll need a 5th character with a 0 byte to mark the end of the 4 character string, unless you use custom char-array output methods. If you set value[3] to something other than 0, you'll start printing bytes next to newArray in the static data area.
There's also no need to explicitly 0 initialize static data.
You can best catch those kinds of errors with valgrind's memcheck tool.

It is printing out a string that starts at the address &newArray[0] and ends at the first 0 in memory thereafter (called the null terminator).
char strArr[] = {"Hello"};
char strArr[] = {'H', 'e', "llo");
char strArr[] = "Hello";
char* strArr = "Hello"; // careful, this is a string literal, you can't mess with it (read-only usually)
...are all null terminated because anything in double quotes gets the null terminator tacked on at the end
char strArr[] = {'H', 'e', 'l', 'l', 'o'};
...is not null terminated, single quotes contain a single character and do not add a null terminator
Here are examples of adding a null terminator...
strArr[3] = '\0';
strArr[3] = NULL;
strArr[3] = 0;

With a bit loss of performance, you can fit into 4 byte.. in 'c-style'.
Print either 4 characters or until \0 is reached:
#include <cstdio>
#include <cstring>
...
//calculate length
size_t totalLength = sizeof(ABC::newArray) / sizeof(ABC::newArray[0]);
char* arrayEnd = (char*)memchr(ABC::newArray, '\0', totalLength);
size_t textLength = arrayEnd != 0 ?
arrayEnd-ABC::newArray : totalLength;
//print
fwrite(
ABC::newArray, //source array
sizeof(ABC::newArray[0]), //one item's size
textLength, //item count
stdout); //destination stream
By the way, try to use std::string and std::cout.

Related

C++ Pointers to arrays

#include <stdio.h>
char strA[80] = "A string to be used for demonstration purposes";
char strB[80];
char *my_strcpy(char *destination, char *source)
{
char *p = destination;
while (*source != '\0')
{
*p++ = *source++;
}
*p = '\0';
return destination;
}
int main(void)
{
my_strcpy(strB, strA);
puts(strB);
}
so my question here is that when i take out the portion:
//*p= '\0';
it prints the exact same answer, so why is this necessary? from my understanding, \0 is a nul portion of memory after a string but since the array strA already contains the nul portion since its in "" is it really necessary?
It seems you already know the importance of the null terminator, but the point is, you defined char strB[80]; in external namespace (with static life span), which causes initialization of the array strB, which sets all bytes of it to zero. That's why you can't observe the difference (because even if you don't append a null character, the rest of strB already is).
Moving the definition of strB makes this visible. strA doesn't need moving because it doesn't matter.
In actuality, this code
while (*source != '\0')
{
*p++ = *source++;
}
// *p = '\0';
When *source reaches a null character, it's not copied to *p, so you need to manualky add a terminator for that.
Your loop stops when it sees the \0 and so it is not copied to the destination and the destination is not NUL terminated. Is that a problem?
Not if your destination buffer is initialized to all 0s
Not if your code is willing to deal with fixed length strings (so the my_strcpy signature would need to change to return the length)
In general YES - the 0 terminated C string is such a common thing that not following the convention is asking for trouble,
Whether you 0 terminate or not the rest of the values will be the same as they were when you started. The 0 termination just makes your character array a "standard C string".
For arguments sake: Assuming you knew every string had space for 80 chars you could just do
for(int i = 0; i < 80; i++)
{
dest[i] = src[i];
}
The effect is the same and assuming the source is 0 terminated the destination will be too.

How to convert a std::string which contains '\0' to a char* array?

I have a string like,
string str="aaa\0bbb";
and I want to copy the value of this string to a char* variable. I tried the following methods but none of them worked.
char *c=new char[7];
memcpy(c,&str[0],7); // c="aaa"
memcpy(c,str.data(),7); // c="aaa"
strcpy(c,str.data()); // c="aaa"
str.copy(c,7); // c="aaa"
How can I copy that string to a char* variable without loosing any data?.
You can do it the following way
#include <iostream>
#include <string>
#include <cstring>
int main()
{
std::string s( "aaa\0bbb", 7 );
char *p = new char[s.size() + 1];
std::memcpy( p, s.c_str(), s.size() );
p[s.size()] = '\0';
size_t n = std::strlen( p );
std::cout << p << std::endl;
std::cout << p + n + 1 << std::endl;
}
The program output is
aaa
bbb
You need to keep somewhere in the program the allocated memory size for the character array equal to s.size() + 1.
If there is no need to keep the "second part" of the object as a string then you may allocate memory of the size s.size() and not append it with the terminating zero.
In fact these methods used by you
memcpy(c,&str[0],7); // c="aaa"
memcpy(c,str.data(),7); // c="aaa"
str.copy(c,7); // c="aaa"
are correct. They copy exactly 7 characters provided that you are not going to append the resulted array with the terminating zero. The problem is that you are trying to output the resulted character array as a string and the used operators output only the characters before the embedded zero character.
Your string consists of 3 characters. You may try to use
using namespace std::literals;
string str="aaa\0bbb"s;
to create string with \0 inside, it will consist of 7 characters
It's still won't help if you will use it as c-string ((const) char*). c-strings can't contain zero character.
There are two things to consider: (1) make sure that str already contains the complete literal (the constructor taking only a char* parameter might truncate at the string terminator char). (2) Provided that str actually contains the complete literal, statement memcpy(c,str.data(),7) should work. The only thing then is how you "view" the result, because if you pass c to printf or cout, then they will stop printing once the first string terminating character is reached.
So: To make sure that your string literal "aaa\0bbb" gets completely copied into str, use std::string str("aaa\0bbb",7); Then, try to print the contents of c in a loop, for example:
std::string str("aaa\0bbb",7);
const char *c = str.data();
for (int i=0; i<7; i++) {
printf("%c", c[i] ? c[i] : '0');
}
You already did (not really, see edit below). The problem however, is that whatever you are using to print the string (printf?), is using the c string convention of ending strings with a '\0'. So it starts reading your data, but when it gets to the 0 it will assume it is done (because it has no other way).
If you want to simply write the buffer to the output, you will have to do this with something like
write(stdout, c, 7);
Now write has information about where the data ends, so it can write all of it.
Note however that your terminal cannot really show a \0 character, so it might show some weird symbol or nothing at all. If you are on linux you can pipe into hexdump to see what the binary output is.
EDIT:
Just realized, that your string also initalizes from const char* by reading until the zero. So you will also have to use a constructor to tell it to read past the zero:
std::string("data\0afterzero", 14);
(there are prettier solutions probably)

Array initialization issue

I need an empty char array, but when i try do thing like this:
char *c;
c = new char [m];
int i;
for (i = 0; i < m; i++)
c[i] = 65 + i;
and then I print c. can see that c = 0x00384900 "НННННННээээ««««««««юоюою"
after cycle it becomes: 0x00384900 "ABCDEFGээээ««««««««юоюою"
How can I solve this problem? Or maybe there is way with string?
If you're trying to create a string, you need to make sure that the character sequence is terminated with the null character \0.
In other words:
char *c;
c = new char [m+1];
int i;
for (i = 0; i < m; i++)
c[i] = 65 + i;
c[m] = '\0';
Without it, functions on strings like printf won't know where the string ends.
printf("%s\n",c); // should work now
If you create a heap array, OS will not initialiase it.
To do so you hvae these options:
Allocate an array statically or globally. The array will be filled with zeroes automatically.
Use ::memset( c, 0, m ); on heap-initialised or stack array to fill it with zeroes.
Use high-level types like std::string.
I believe that's your debugger trying to interpret the string. When using a char array to represent a string in C or C++, you need to include a null byte at the end of the string. So, if you allocate m + 1 characters for c, and then set c[m] = '\0', your debugger should give you the value you are expecting.
If you want a dynamically-allocated string, then the best option is to use the string class from the standard library:
#include <string>
std::string s;
for (i = 0; i < m; i++)
s.push_back(65 + i);
C strings are null terminated. That means that the last character must be a null character ('\0' or just 0).
The functions that manipulate your string use the characters between the beginning of the array (that you passed as parameter, first position in the array) and a null value. If there is no null character in your array the function will iterate pass it's memory until it finds one (memory leak). That's why you got some garbage printed in your example.
When you see a literal constant in your code, like printf("Hello");, it is translate into an array of char of length 6 ('H', 'e', 'l', 'l', 'o' and '\0');
Of course, to avoid such complexity you can use std::string.

Why am i getting two different strings?

I wrote a very simple encryption program to practice c++ and i came across this weird behavior. When i convert my char* array to a string by setting the string equal to the array, then i get a wrong string, however when i create an empty string and add append the chars in the array individually, it creates the correct string. Could someone please explain why this is happening, i just started programming in c++ last week and i cannot figure out why this is not working.
Btw i checked online and these are apparently both valid ways of converting a char array to a string.
void expandPassword(string* pass)
{
int pHash = hashCode(pass);
int pLen = pass->size();
char* expPass = new char[264];
for (int i = 0; i < 264; i++)
{
expPass[i] = (*pass)[i % pLen] * (char) rand();
}
string str;
for (int i = 0; i < 264; i++)
{
str += expPass[i];// This creates the string version correctly
}
string str2 = expPass;// This creates much shorter string
cout <<str<<"\n--------------\n"<<str2<<"\n---------------\n";
delete[] expPass;
}
EDIT: I removed all of the zeros from the array and it did not change anything
When copying from char* to std::string, the assignment operator stops when it reaches the first NULL character. This points to a problem with your "encryption" which is causing embedded NULL characters.
This is one of the main reasons why encoding is used with encrypted data. After encryption, the resulting data should be encoded using Hex/base16 or base64 algorithms.
a c-string as what you are constructing is a series of characters ending with a \0 (zero) ascii value.
in the case of
expPass[i] = (*pass)[i % pLen] * (char) rand();
you may be inserting \0 into the array if the expression evaluates to 0, as well as you do not append a \0 at the end of the string either to assure it being a valid c-string.
when you do
string str2 = expPass;
it can very well be that the string gets shorter since it gets truncated when it finds a \0 somewhere in the string.
This is because str2 = expPass interprets expPass as a C-style string, meaning that a zero-valued ("null") byte '\0' indicates the end of the string. So, for example, this:
char p[2];
p[0] = 'a';
p[1] = '\0';
std::string s = p;
will cause s to have length 1, since p has only one nonzero byte before its terminating '\0'. But this:
char p[2];
p[0] = 'a';
p[1] = '\0';
std::string s;
s += p[0];
s += p[1];
will cause s to have length 2, because it explicitly adds both bytes to s. (A std::string, unlike a C-style string, can contain actual null bytes — though it's not always a good idea to take advantage of that.)
I guess the following line cuts your string:
expPass[i] = (*pass)[i % pLen] * (char) rand();
If rand() returns 0 you get a string terminator at position i.

c++ how to add a zero bits byte or null to a string

I am doing a simple client implementation of TFTP.
Here i need to send read request in following format
/* send request
2 bytes string 1 byte string 1 byte
------------------------------------------------------
RRQ/ | 01/02 | Filename | 0 | Mode | 0 |
WRQ -------------------------------------------------
*/
in between i have to insert 1 byte zero bits value .
But i am not able to add that value.
Also if i add a 1 zero bits byte.. which actually means a string terminating character
than how to get proper strlen value.
If any one can help me with this...
enter code here
const char opcode_read[2] ={'0','1'};
const char opcode_write[2] ={'0','2'};
const char opcode_data[2] ={'0','3'};
const char opcode_acknowledge[2] ={'0','4'};
const char opcode_error[2] ={'0','5'};
const char mode_netascii[] = "netascii\0";
char blk_read_request[100];
char file_name[] = "rfc0791.txt\0";
memcpy(blk_read_request, opcode_read, 2);
memcpy(&blk_read_request[2], file_name, strlen(file_name) + 1);
memcpy(&blk_read_request[2 + strlen(file_name)], mode_netascii, strlen(mode_netascii) + 1);
for (int i = 0; i < strlen(blk_read_request); i++) {
cout << i << " : " << blk_read_request[i] << " " << std::bitset<CHAR_BIT > (blk_read_request[i]) << "\n";
}
If you want to transfer the null across, not only must you memcpy with "strlen(filename) + 1", but you'll also need to update the destination pointer for the subsequent memcpys accordingly.
memcpy(&blk_read_request[2 + strlen(file_name) + 1], mode_netascii, strlen(mode_netascii) + 1);
Note the extra +1 in there.
For the record, being C++, you might want want to consider using a higher-level class than "char *" which can handle embedded null characters.
For example, the following prints "8", and opens up std::stringstream as a better way of forming your packets:
#include <string>
#include <iostream>
int main()
{
std::string x = "foo";
x += '\0';
x += "bar";
x += '\0';
std::cout << x.length() << std::endl;
}
This is automatic in C++ strings.
This:
const char mode_netascii[] = "netascii";
Is equivalent to this:
const char mode_netascii[] = { 'n', 'e', 't', 'a', 's', 'c', 'i', 'i', '\0' };
If you need to deal with data that will (or might) include null bytes then you'll generally want to avoid using C-style strings and the functions that deal with them. Use character/byte arrays and keep a length associated with the length of the data in the buffers.
In C++ vectors of bytes (or char) would work great for this.
Also in C++, the std::string type can contain null characters just fine; however, I'd suggest avoiding their use and sticking with std::vector<char> since it would be all too easy to fall into some bug traps of passing the result of string::c_str() to something that expects null terminated strings.
char *total_send_string = malloc(2+strlen(file_name)+sizeof(Mode)+3);
memset(total_send_string, 0, strlen(total_send_string);
//Then copy each member of the total send packet into the correct offset
//Now you have the correct result