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.
Related
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;
}
char ch[] = {'h', 'e', 'l', 'l', 'o'};
char* p = ch;
while(*p){
std::cout << *p << std::endl;
++p;
}
This prints the elements of array + garbage but,
int ch[] = {1, 2, 3, 4};
int* p = ch;
while(*p){
std::cout << *p << std::endl;
++p;
}
This prints just the elements of array no garbage.
I am just a beginner to c++ and i am failing to figure out the reason behind such behaviour.
Need some help with this.
while (*p) { continues until it hits a value of 0. In neither case have you ensured that there is a 0 terminating your arrays and it's just luck that one worked whilst the other didn't.
Due to the lack of a defined end to your string you will continue to iterate beyond the intended array of characters, which will output data held within adjacent memory. Character strings are typically set up in c/c++ to terminate by null character ('\0') which allows the array to iterate until *p=='\0'.
If you add an element to the array, set the last element to '\0', and set the while loop to run until *p=='\0', you should achieve the desired output.
This will prevent the loop from overrunning your intended bounds and is a good practice in software security in addition to being functionally important, as outputting additional memory can sometimes be exploited in applications.
I am having a problem with strcat() function. Please explain me how that function works.
char a[] = "AT";
char x[] = "KA";
char y = 'X';
sen(a);
s = strcat(a, "+CMGF=");
sen(s);
s = strcat(s, "\r\n");
sen(s);
s = strcat(s, &y);
sen(s);
getch();
return 0;
S is a glopal character pointer & sen() is a function just to print the data of the contained string. Now the final value of s is "AT+CMGF=\r\nXKA".
It automatically appends the x array at the last in the s, though i haven't written code of it.
Why is it so? Please explain me
char a[] = "AT" will create a string that is exactly 3 characters long. When you then strcat something else to it, it writes into the memory after the a variable. Which just happens to be some unused space before x. [Technically, what happens when you write outside space of a is undefined behaviour, and there is absolutely no guarantee that the KA from x actually is just that precise distance from a, or that the code doesn't crash in some way - undefined behaviour means that the C++ standard doesn't explain what will happen, and the compiler and/or runtime library is allowed to crash or behave in a way that "isn't what you expect" in some other way during such behaviour - ANYTHING that your system could possibly do is allowed when UB is invoked]
Make sure that the destination string of a is BIG ENOUGH to hold your string, and you won't have that problem.
You are in the realm of undefined behavior. More specifically, what it is doing is this:
char a[] = "AT";
char x[] = "KA";
char y = 'X';
s = strcat(a, "+CMGF="); // a is a constant string, so this is NOT fine. You should be calling s = strcat(s, a) and then s = strcat(s, "+CMGF=")
s = strcat(s, "\r\n"); // "\r\n" = "\r\n\0", so it is also fine
s = strcat(s, &y); // y is a char, and is NOT null-terminated, so it is NOT fine
It just so happened that the compiler you are using placed y and x side by side in the section of memory, so strcat is operating until it finds the first null-terminator. And all of this is assuming that s has enough space allocated for it to hold all of these concatenations (if not, you are in another realm of undefined behavior).
To correct all of your known problems:
char s[100] = {0}; // showing declaration of s of sufficient size
char a[] = "AT";
char x[] = "KA";
char y[] = "X";
sen(s); // shows empty string
s = strcat(s, a); // append a to empty s
s = strcat(s, "+CMGF="); // append "+CMGF=" to the end of new s
sen(s); // will now show "AT+CMGF="
s = strcat(s, "\r\n"); // add "\r\n"
sen(s); // will now show "AT+CMGF=\r\n"
s = strcat(s, y); // append y
sen(s); // will now show "AT+CMGF=\r\nX"
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.