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"
Related
As I know, if we declare char* in our program then it gives memory from read-only area, so we are not able to change a char at any position in the array.
char *ch = "sitaram";
ch[2] = 'y';
The above code will not run properly, as we are changing read-only memory.
One approach is we can declare our char array as
char ch[] = "sitaram";
and then we can change a value at an index.
Is there any way where I can change a char value at any index in a char*?
Use the modern C++ approach for mutable string values
std::string str{"sitaram"};
str[2] = 'y';
String literals (i.e. values enclosed in "") are by default of type const char[n] (where n is the length of the string literal +1 for the null character) in C++ and because of that they are immutable, any attempt to modify them results in undefined behavior.
When you say:
char *ch = "sitaram";
The compiler does the following:
it allocates the string "sitaram" at program start (static storage duration). This string can be put into read-only memory.
when your program arrives at this line, it allocates the pointer ch, and makes this pointer to point to the statically allocated "sitaram" string.
if you do ch[2] = 'y', then you're trying to modify the 3rd character of the statically allocated string. Usually, you get a crash (because it is in read-only memory)
On the other hand, if you do the following:
char ch[] = "sitaram";
When the program hit this line, it allocates memory for the array ch[] (for 8 chars), then copies the string "sitaram" into this memory. If you do ch[2] = 'y', then you modify this allocated memory, which is perfectly fine to do.
If you want to modify a string with char *, it should point to a memory which is modifiable. For example:
char ch[] = "sitaram";
char *xx = ch;
xx[2] = 'y'; // it is the same as ch[2] = 'y';
Using char arrays:
char text[] = "sitaram";
text[3] = 'o';
char * p = &text[0];
p[4] = 'x';
cout << text;
Why does this code produce runtime issues:
char stuff[100];
strcat(stuff,"hi ");
strcat(stuff,"there");
but this doesn't?
char stuff[100];
strcpy(stuff,"hi ");
strcat(stuff,"there");
strcat will look for the null-terminator, interpret that as the end of the string, and append the new text there, overwriting the null-terminator in the process, and writing a new null-terminator at the end of the concatenation.
char stuff[100]; // 'stuff' is uninitialized
Where is the null terminator? stuff is uninitialized, so it might start with NUL, or it might not have NUL anywhere within it.
In C++, you can do this:
char stuff[100] = {}; // 'stuff' is initialized to all zeroes
Now you can do strcat, because the first character of 'stuff' is the null-terminator, so it will append to the right place.
In C, you still need to initialize 'stuff', which can be done a couple of ways:
char stuff[100]; // not initialized
stuff[0] = '\0'; // first character is now the null terminator,
// so 'stuff' is effectively ""
strcpy(stuff, "hi "); // this initializes 'stuff' if it's not already.
In the first case, stuff contains garbage. strcat requires both the destination and the source to contain proper null-terminated strings.
strcat(stuff, "hi ");
will scan stuff for a terminating '\0' character, where it will start copying "hi ". If it doesn't find it, it will run off the end of the array, and arbitrarily bad things can happen (i.e., the behavior is undefined).
One way to avoid the problem is like this:
char stuff[100];
stuff[0] = '\0'; /* ensures stuff contains a valid string */
strcat(stuff, "hi ");
strcat(stuff, "there");
Or you can initialize stuff to an empty string:
char stuff[100] = "";
which will fill all 100 bytes of stuff with zeros (the increased clarity is probably worth any minor performance issue).
Because stuff is uninitialized before the call to strcpy. After the declaration stuff isn't an empty string, it is uninitialized data.
strcat appends data to the end of a string - that is it finds the null terminator in the string and adds characters after that. An uninitialized string isn't gauranteed to have a null terminator so strcat is likely to crash.
If there were to intialize stuff as below you could perform the strcat's:
char stuff[100] = "";
strcat(stuff,"hi ");
strcat(stuff,"there");
Strcat append a string to existing string. If the string array is empty, it is not going go find end of string ('\0') and it will cause run time error.
According to Linux man page, simple strcat is implemented this way:
char*
strncat(char *dest, const char *src, size_t n)
{
size_t dest_len = strlen(dest);
size_t i;
for (i = 0 ; i < n && src[i] != '\0' ; i++)
dest[dest_len + i] = src[i];
dest[dest_len + i] = '\0';
return dest;
}
As you can see in this implementation, strlen(dest) will not return correct string length unless dest is initialized to correct c string values. You may get lucky to have an array with the first value of zero at char stuff[100]; , but you should not rely on it.
Also, I would advise against using strcpy or strcat as they can lead to some unintended problems.
Use strncpy and strncat, as they help prevent buffer overflows.
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
char p [] = "TEST";
strcat (p, "VAL");
cout << p;
return 0;
}
If what I understand is correct, a statement like char p [] = "TEST"; will allocate space from stack. When I call strcat() for such a string how the storage for p[] is adjusted to accommodate extra characters?
Last cout prints "TESTVAL". Is it valid to call strcat like this? If yes, how this works? I might be having problem with my understanding, but feeling like I lost touch. So this could easily be a dumb question. Please shed some light.
The storage is not adjusted, the call is not valid, and the behaviour of the code is undefined.
when you write
char buffer[] = "some literal";
it is expanded to
char buffer[sizeof("some literal")] = "some literal";
which has exact size to store "some literal" and nothing more.
when you concate another string in the end of the current buffer- you write beyond the boundries of the array - having undefined behavior.
another issue that in C++, we usually use std::string to handle strings, which does all the memory adjustment for us automatically.
p reserves space for 5 characters (4 + 1 for the null terminator). You are then appending 3 more characters which needs room for 8 (7 + 1 for the null). You don't have enough room for that and will be overwriting the stack. Depending on your compiler and build settings, you may not see any difference as potentially, the compiler leaves spaces between stack variables. On an optimised release build, you will probably get a crash.
If you change your code to look like this, you should see that sentinel1 & 2 are no longer 0 (it depends on the compiler which one will get trashed).
#include<iostream>
#include<string.h>
using namespace std;
int main()
{
int sentinel1 = 0;
char p [] = "TEST";
int sentinel2 = 0;
strcat (p, "VAL");
cout << p << sentinel1 << sentinel2;
return 0;
}
I'm making a lexical analyzer and this is a function out of the whole thing. This function takes as argument a char, c, and appends this char to the end of an already defined char* array (yytext). It then increments the length of the text (yylen).
I keep getting segfaults on the shown line when it enters this function. What am I doing wrong here? Thanks.
BTW: can't use the strncpy/strcat, etc. (although if you want you can show me that implementation too)
This is my code:
extern char *yytext;
extern int *yylen;
void consume(char c){
int s = *yylen + 1; //gets yylen (length of yytext) and adds 1
//now seg faults here
char* newArray = new char[s];
for (int i = 0;i < s - 1;i++){
newArray[i] = yytext[i]; //copy all chars from existing yytext into newArray
}
newArray[s-1] = c; //append c to the end of newArray
for (int i = 0;i < s;i++){ //copy all chars + c back to yytext
yytext[i] = newArray[i];
}
yylen++;
}
You have
extern int *yylen;
but try to use it like so:
int s = (int)yylen + 1;
If the variable is an int *, use it like an int * and dereference to get the int. If it is supposed to be an int, then declare it as such.
That can t work:
int s = (int)yylen + 1; //gets yylen (length of yytext) and adds 1
char newArray[s];
use malloc or a big enought buffer
char * newarray=(char*)(malloc(s));
Every C-style string should be null-terminated. From your description it seems you need to append the character at c. So, you need 2 extra locations ( one is for appending the character and other for null-terminator ).
Next, yylen is of type int *. You need to dereference it to get the length (assuming it is pointing to valid memory location ). So, try -
int s = *yylen + 2;
I don't see the need of temporary array but there might be a reason why you are doing it. Now,
yytext[i] = newArray[i]; //seg faults here
you have to check if yytext is pointing to a valid write memory location. If yes, then is it long enough to fill the appending character plus null terminator.
But I would recommend using std::string than working with character arrays. Using it would be a one liner to solve the problem.
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.