What is happening when i write array[i] = '\0' inside a for loop?
char arrayPin[256];
for(int i = 0; i<256; i++)
{
arrayPin[i] = '\0';
}
The program attempts to access memory at the location of <base address of 'array'> + (<sizeof array element> * 'i') and assign the value 0 to it (binary 0, not character '0'). This operation may or may not succeed, and may even crash the application, depending upon the state of 'array' and 'i'.
If your array is of type char* or char[] and the assignment operation succeeds, then inserting the binary 0 at position 'i' will truncate the string at that position when it is used with things that understand C-style strings (printf() being one example).
So if you do this in a for loop across the entire length of the string, you will wipe out any existing data in the string and cause it to be interpreted as an empty/zero-length string by things that process C-style strings.
char arrayPin[256];
After the line above, arrayPin in an uninitialized array whose contents are unknown (assuming it is not a global).
----------------------------
|?|?|?|?|?|?|?|?|?|?|...|? |
----------------------------
byte: 0 1 2 3 4 5 6 7 8 9 255
Following code:
for(int i = 0; i<256; i++)
{
arrayPin[i] = '\0';
}
initializes every arrayPin element to 0:
----------------------------
|0|0|0|0|0|0|0|0|0|0|...|0 |
----------------------------
byte: 0 1 2 3 4 5 6 7 8 9 255
I suppose you have something like char *array. In this case It will write character with the code 0x00 into ith position.
This is quite useful when you work with ANSI strings. \0 indicates the end of the string. For example:
char str[] = "Hello world";
cout << str << endl; // Output "Hello world"
str[5] = '\0';
cout << str << endl; // Output just "Hello"
Related
I am looking at a unique example here and am trying to understand why his snippet behaves the way it does
// uninitialized mem
char test[99999];
//
test[0] = 'a';
test[1] = 'b';
test[2] = 'c';
test[3] = 'd';
test[4] = 'e';
test[5] = 'f';
test[6] = 'g';
for (int i = 0; i < 99999; i++) {
cout << (&test[i])[i] << endl;
}
In particular, what is happening in memory for the output to skip a character?
output:
a
c
e
g
..
This is what is happening:
An array is just a contiguous chunk of memory.
&test
Is getting the address of that index of the starting point of array. Not the value.
When you add [some number], it counts up the number times the size of the data type, in this case each char is a byte.
So when you do
&test[i]
that means the starting address + i bytes.
when you do
(&test[i])[i]
You are doing i bytes from the starting address, and then treat that as the starting address and go up i more bytes.
So in your iterations:
(&test[0])[0] // index 0 + 0 = 0
(&test[1])[1] // index 1 + 1 = 2
(&test[2])[2] // index 2 + 2 = 4
(&test[3])[3] // index 3 + 3 = 6
It should become a bit more obvious when you consider what the array indexing is actually doing.
Given an array test, you usually access the nth element of test with test[n]. However, this is actually the equivalent of *(test+n). This is because addition on pointers automatically multiplies the amount you add with the size of the type being pointed to. This means the pointer will then be pointing at the second item in the array if you add one to the pointer, the third item if you add two, and so on.
The code you provide then references that value, so you end up with &(*(test+n)). The reference (&) and the dereference (*) operations then cancel each other out, which means you end up with just test+n.
The code then does another array index on that value, so you end up with (test+n)[n], which again may be written as *((test+n)+n). If you simplify that, you get *(test+n+n), which may be rewritten as *(test+2*n).
Clearly then, if you convert that back to array indexing notation, you end up with test[2*n], which indicates in simple form that you'll be querying every other element of the array.
I'm having some issues right now, attempting to append a char array onto a c++ string after setting some of the values of the c++ string, and I don't see why. I was wondering if any of you know what's going.
Here's the code I'm trying to run:
string test = "";
test.resize(1000);
char sample[10] = { "Hello!" };
test[0] = '1';
test[1] = '2';
test[2] = '3';
test[3] = '4';
test += sample;
Running it through a debugger, it seems that test is just "1234", and the "Hello" is never added.
Thanks in advance!
It is added, but after the 1000 characters you already have in the string (4 of them are the 1234, and 996 are '\0' characters)`.
The resize function does allocate 1000 characters for the string object, but also sets the length to 1000. That's why sometimes what you want to do instead is use reserve
This is normally what I would do:
string test = "";
test.reserve(1000); // length still 0, capacity: 1000
char sample[10] = { "Hello!" };
test.push_back('1'); // length is 1
test.push_back('2'); // length is 2
test.push_back('3'); // length is 3
test.push_back('4'); // length is 4
test += sample; // length is now 10
Or if you want to do it your way:
string test = "";
test.resize(1000); // length is 1000
char sample[10] = { "Hello!" };
test[0] = '1'; // length is 1000
test[1] = '2'; // length is 1000
test[2] = '3'; // length is 1000
test[3] = '4'; // length is 1000
test.resize(4); // length is now 4, but the internal buffer still has a capacity of 1000 characters
test += sample; // length is now 10
I think the problem is when you did test.resize(1000) it added 1000 null characters ('\0') to the string. The debugger probably sees null characters as end-of-string markers. So any text added after those null characters won't get displayed.
Say text equals this ('_' = null character end of line marker):
test = "1234_______________Hello!";
^
Debugger thinks text ends here
In the C++ Standard std:string follows an exponential growth policy, therefore I suppose the capacity() of string during concatenation will always be increased when necessary. However, when I test test.cpp, I found that in the for-loop, only every two times will the capacity() be shrunk back to length() during assignment.
Why isn't this behavior depending on the length of string, but depending on how frequent I change the string? Is it some kind of optimization?
The following codes are tested with g++ -std=c++11.
test.cpp:
#include <iostream>
int main(int argc, char **argv) {
std::string s = "";
for (int i = 1; i <= 1000; i++) {
//s += "*";
s = s + "*";
std::cout << s.length() << " " << s.capacity() << std::endl;
}
return 0;
}
And the output will be like this:
1 1
2 2
3 4
4 4
5 8
6 6 // why is capacity shrunk?
7 12
8 8 // and again?
9 16
10 10 // and again?
11 20
12 12 // and again?
13 24
14 14 // and again?
15 28
16 16 // and again?
17 32
...
996 996
997 1992
998 998 // and again?
999 1996
1000 1000 // and again?
When you do this:
s = s + "*";
You're doing two separate things: making a new temporary string, consisting of "*" concatenated onto the end of the contents s, and then copy-assigning that new string to s.
It's not the + that's shrinking, it's the =. When copy-assigning from one string to another, there's no reason to copy the capacity, just the actual used bytes.
Your commented-out code does this:
s += "*";
… is only doing one thing, appending "*" onto the end of s. So, there's nowhere for the "optimization" to happen (if it happened, it would be a pessimization, defeating the entire purpose of the exponential growth).
It's actually not convered by the C++ standard what happens to capacity() when strings are moved, assigned, etc. This could be a defect. The only constraints are those derivable from the time complexity specified for the operation.
See here for similar discussion about vectors.
So I am trying to simply do a std::string == "string-literal" which would work just fine, except that I am creating my string with
std::string str(strCreateFrom, 0, strCreateFrom.find(' '));
and find returns string::npos now both of these contain the string "submit" however == returns false, now I have narrowed this down to the fact that the sizes are "different" even though they really aren't. str.size() is 7 and strlen("submit") is 6. Is this why == is failing, I assume it is but I don't see why... shouldn't it check to see if the last char of dif is \0 as is the case in this situation?
And is there anyway that I can get around this without having to using compare and specify the length to compare or change my string?
Edit:
std::string instruction(unparsed, 0, unparsed.find(' '));
boost::algorithm::to_lower(instruction);
for(int i = 0; i < instruction.size(); i++){
std::cout << "create from " << (int) unparsed[i] << std::endl;
std::cout << "instruction " << (int) instruction[i] << std::endl;
std::cout << "literal " << (int) "submit"[i] << std::endl;
}
std::cout << (instruction == "submit") << std::endl;
prints
create from 83
instruction 115
literal 115
create from 117
instruction 117
literal 117
create from 98
instruction 98
literal 98
create from 77
instruction 109
literal 109
create from 105
instruction 105
literal 105
create from 116
instruction 116
literal 116
create from 0
instruction 0
literal 0
0
EDIT:
For more clarification as to why I'm confused I read the basic_string.h header and saw this:
/**
* #brief Compare to a C string.
* #param s C string to compare against.
* #return Integer < 0, 0, or > 0.
*
* Returns an integer < 0 if this string is ordered before #a s, 0 if
* their values are equivalent, or > 0 if this string is ordered after
* #a s. Determines the effective length rlen of the strings to
* compare as the smallest of size() and the length of a string
* constructed from #a s. The function then compares the two strings
* by calling traits::compare(data(),s,rlen). If the result of the
* comparison is nonzero returns it, otherwise the shorter one is
* ordered first.
*/
int
compare(const _CharT* __s) const;
Which is called from operator== so I am trying to find out why the size dif matters.
I didn't quite understand your question more details may be needed, but you can use the c compare which shouldn't have issues with null termination counting.
You could use:
bool same = (0 == strcmp(strLiteral, stdTypeString.c_str());
strncmp also can be used to compare only a given number of chars in a char array
Or try to fix the creation of the stdstring
Your unparsed std::string is already bad. It already contains the extra null in the string, so what you should look at is how it is being created.
Like I mentioned before mystring[mystring.size() -1] is the last character not the terminating null so if you see a '\0' there like you do in your output it means the null is treated like part of the string.
Try to trace back your parsed input and keep making sure that mystring[mystring.size() -1] is not '\0'.
To answer your size diff question:
The two strings are not the same the literal is shorter and doesn't have a null.
Memory of std::string->c_str() [S,u,b,m,i,t,\0,\0] length = 7, memory size = 8;
Memory of literal [S,u,b,m,i,t,\0] length = 6, memory size = 7;
Compare stops comparing when it reaches the the terminating null in the literal but it uses the stored size for the std::string which is 7 seeing that literal terminated at 6 but the std is size 7 it will say that std is larger.
I think if you do the following it will return that the strings are the same (because it will create an std string with an extra null on the right side as well):
std::cout << (instruction == str("submit", _countof("submit"))) << std::endl;
PS: This is a common error made when taking a char* and making an std::string out of it, frequently just the array size itself is used, but that includes the terminating zero which std::string will add anyway. I believe that something like this is happening to your input somewhere and if you get add a -1 wherever that is everything will work as expected.
I have a question about a string in C++. As per below code, I would like to know where will the loops stop at. Will it take the null in index 3 or index 4?
#include <cstdio>
int main ( ) {
char name [20] = "Foo";
name [4] = '\0';
for (int i = 0; name[i] != '\0'; i++) {
printf("This is the value of i so far in the loop : %d \n",i);
}
printf("This is the value of i : %d \n",i);
return 0;
}
the reason I am asking this is,I don't understand why in my homework they gave us something like this. Is there any reason to make '\0' in index 4?
"Foo" is actually {'F','o','o','\0'}, and fits index 0,1,2,3.
Index 4 up to 19 are default initialized (hence 0-ed). And index 4 is assigned later with '\0'.
The loop ends when the first '\0' is matched, so that value 0,1,2 are printed.
Out of the loop i shold ... ahem .. be undefined! (it is declared inside the loop scope), but if your compiler didn't clean up you most likely will print 3.
A typycal example of C++ (note #include<cstdio>, but no std never referenced...) taught by a C instructed teacher.
Give my congrats to him!
Is there any reason to make '\0' in index 4?
Absolutely none.
This line:
char name [20] = "Foo";
Initializes the array as follows:
name[0] <-- 'F' First char of "Foo"
name[1] <-- 'o' Second char of "Foo"
name[2] <-- 'o' Third char of "Foo"
name[3] <-- '\0' Fourth char of "Foo"
name[4..19] <-- 0 Extra spaces in array get zero-filled
So, this line:
name [4] = '\0';
writes a zero to a location already guaranteed to be zero.
So, there is a zero at index 3 (it is the final char in "Foo"). There is a zero in all of the locations 4-19 (since the initializer is smaller than the array). And, redundantly, there is a zero written to index 4.
I think it should be 3:
name[0]='F' name[1]='o' name[2]='o' name[3]='\0' name[4]='\0'