If I set an array variable a[]="abc" , and then set another array variable b[]={'d','e','f'} ,my last output code is printf("%s",b) ,it's output value is "defabc",why? My output is array b but the output value will output array b first and then output array a second.
The whole code is on bellow.
#include<stdio.h>
void main(){
char a[]="abc";
char b[]={'d','e','f'};
printf("%s",b);
}
The output is "defabc".
And the string length of array b is 7 why?
In C all strings should be null (i.e. \0) terminated, so your second variable should look like the following:
char b[] = {'d', 'e', 'f', '\0'};
You might be curious why "defabc" is printed with your code. The answer is, all local variables are stored in a stack-based memory layout. So your memory layout looks like this:
|'d' | <-- b
|'e' |
|'f' |
|'a' | <-- a
|'b' |
|'c' |
|'\0'|
Also note that printf("%s", ...) reads until it reach a \0, so printf("%s", a) works as expected but printf("%s", b) prints "defabc".
You need a null terminator at the end of both strings. your second string does not have it as its defined as an array of characters.
Correct ways to declare a string
char b[] = { 'd', 'e', 'f', '\0' }; // null terminator required
or
char b[] = "def"; // null terminator added automatically
So, this code will print def as output
#include <stdio.h>
int main() {
char a[] = "abc";
char b[] = { 'd', 'e', 'f', '\0' };
printf("%s", b);
return 0;
}
Related
My goal is to generate a new array with the correct amount of spots and copy an old character array into it.
When using strcpy_s, an exception is thrown. I can not figure out why the exception is being thrown which states that the Buffer is too small. I can not use vectors or strings. How can I fix this using strcpy_s and char arrays?
char str[4] = { 't', 'e', 's', 't' };
int allocated = 4;
char * reservedString = new char[allocated]();
strcpy_s(reservedString, allocated, str);
EDIT:
Changing my code to add one to the array gives me the same "buffer too small" exception.
char str[4] = { 't', 'e', 's', 't' };
int allocated = 4;
char * reservedString = new char[allocated+1]();
strcpy_s(reservedString, allocated, str);
EDIT 2:
As someone commented str needed to be set to 5 in size and have a null terminator included. Thank you this fixed my problem.
Updated code:
char str[5] = { 't', 'e', 's', 't', '\0'};
int allocated = 5;
char * reservedString = new char[allocated]();
strcpy_s(reservedString, allocated, str);
You need five characters to store the zero-terminated string "test". Your str array is just four characters, with no zero terminator. If you want a zero-terminator, declare it like this:
char str[] = "test";
Then you need of course
int allocated = 5;
And after that:
char * reservedString = new char[allocated];
strcpy_s(reservedString, allocated, str);
char str[4] = { 't', 'e', 's', 't' }; is a 4-byte array in the memory. It is not a string, and it is completely random where a "trailing" zero will occur after these 4 bytes, and an arbitrary amount of other data in between.
However, strcpy_s() expects copying a zero-terminated string, just one of the extras it does is checking if the source string will fit into the destination. It will not, that is why you get the error.
[...] the following errors are detected at runtime and call the currently installed constraint handler function:
* src or dest is a null pointer
* destsz is zero or greater than RSIZE_MAX
* destsz is less or equal strnlen_s(src, destsz); in other words, truncation would occur
* overlap would occur between the source and the destination strings
You get the third one, a truncation of the "garbage" bytes would occur.
str is not a string. A string is a sequence of non-NUL characters, terminated by NUL.
You should pass the size of the buffer to strcpy_s(), not the maximum string-size (which is one less).
That is, if you should use strcpy_s() at all. You shouldn't.
Use strcpy(), or as you already have the exact size, memcpy() or std::copy_n().
As a side-note, zeroing memory just to turn around and overwrite it is a pointless waste.
You are not allocating the proper memory:
char str[4] = { 't', 'e', 's', 't' };
It allocates 5 bytes, 4 for each character plus the null terminator.---
Do:
char str[4] = { 't', 'e', 's', 't' };
char * reservedString = new char[5]();
strcpy_s(reservedString, allocated, str);
Or:
char str[4] = { 't', 'e', 's', 't' };
char * reservedString = new char[5]();
strcpy(reservedString, str);
I can't figure out why is this code not working. (I know how to fix it, but I'm interested in this particular solution) It takes one string and puts is on the end of other string. x = "abc", y = "def" and after executing foo, x = "abcdef". After executing my code I only get "abc".
#include <stdio.h>
#define MAX 10
void foo(char *x, char *y){
while(*x++);
while(*y){
*x++ = *y++;
}
*x = '\0';
}
int main(void){
char x[MAX+1], y[MAX+1];
scanf("%s %s", x, y);
foo(x, y);
printf("%s", x);
return 0;
}
If I do this, the code works perfectly fine.
while(*x) x++;
This expression will increment x even after the null is discovered and the loop completes:
while(*x++);
In this case, you are appending the second string AFTER the null, so that part of the string isn't "seen". The string becomes "abc\0def".
The following will NOT increment x when the null is found, so *x will point to null after the loop completes:
while(*x) x++;
Therefore, in this case, your string comes out correctly as, "abcdef".
This loop:
while(*x++);
moves x past the null terminator. So your c-string ends at the same place as it did before. The characters in y are written to x, but they come after the null terminator, so they are not printed out.
When you use
while(*x++);
x points to one past the null character at the end of the statement. In effect, you end up with
x[] = {'a', 'b', 'c', '\0', 'd', 'e', 'f', '\0', ....}
in main.
I've noticed a weird discrepancy in C++.
Say I have this code:
const char myChars[] = "12345";
std::cout << myChars;
The output is: 12345
However, if I then change it to:
const char myChars[] = {'1','2','3','4','5'};
std::cout << myChars;
Then the output is: 12345__SOME_RANDOM_DATA_IN_MEMORY__
Why is it that cout appears to know the length of the first version but not the length of the second version? Also, does cout even know the length?
Thanks.
There is no null terminator in your second example.
const char myChars[] = {'1','2','3','4','5', 0};
would work fine.
Strings literals require a null-terminator to indicate the end of the string.
See this stackoverflow answer for more detailed information: https://stackoverflow.com/a/2037245/507793
As for your first example, when you make a string literal using quotes like "Hello", that is roughly equivalent to {'H', 'e', 'l', 'l', 'o', 0}, as the null-terminator is implicit when using quotes.
Ask the compiler for sizeof(myChars) and notice the difference. The end of a string is marked by a null character, implicit when you use "".
When setting mychars[] with "12345", you implicitly add a '\0' to the end of it, telling the program that this is the end of the string, wich you dont with {'1','2','3','4','5'};
C strings are implemented as char arrays that end with a special character \0.
String literals have it implicitly. While the curly braces array initialization doesn't add it.
You need to add it manually
const char myChars[] = {'1','2','3','4','5', '\0'};
or simply
const char myChars[] = {'1','2','3','4','5', 0};
Since '\0' == 0 numerically.
const char myChars[] = {'1','2','3','4','5','\0'};
do not forget to add null terminate string
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.
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