I am trying to append two chars but for some reason I am getting a segmentation fault.
My code is like;
#include <string.h>
char *one = (char*)("one");
char *two = (char*)("two");
strcat(one, two);
and I seem to be getting a segmentation fault at strcat(one, two), why is that?
http://www.cplusplus.com/reference/clibrary/cstring/strcat/
the first parameter to strcat, must be big enough to hold the resulting string
try:
//assuming a,b are char*
char* sum = new char[strlen(a) +strlen(b)+1];
strcpy(sum,a);
strcat(sum,b);
There should be enough legal memory to hold the entire string.
char *one = new char[128]; //allocating enough memory!
const char *two = "two"; //"two" is const char*
strcpy(one, "one");
strcat(one, two); //now the variable "one" has enough memory to hold the entire string
By the way, if you prefer using std::string over char* in C++, such thing would be easier to handle:
#include<string>
std::string one = "one";
std::string two = "two";
one = one + two; //Concatenate
std::cout << one;
Output:
onetwo
There are two reasons for this.
If you have a pointer initialized to a string literal, that memory is read-only and modifying it will result in undefined behavior. In this case, if you try to append a string to a string literal, you'll be modifying this sort of memory, which will result in problems.
When using strcat you need to guarantee that space exists for the concatenation of the string at the location you're specifying. In this case, you cannot guarantee that, since a string literal is only guaranteed to have enough space to hold the literal itself.
To fix this, you'll want to explicitly allocate a buffer large enough to hold the concatenation of the two strings, including the null terminator. Here's one approach:
char* buffer = malloc(strlen(one) + strlen(two) + 1);
strcpy(buffer, one);
strcat(buffer, two);
Hope this helps!
The seg fault is because you attempt to write to read only memory. The first action of the strcat is to copy of 't' from the first entry of two into the null at the end of "one". So strictly the seg fault is not due to lack of storage - we never get that far. In fact this code will also likely give you a seg fault:
char* one = "one";
char* two = "";
strcat(one, two);
All this tries to do is copy a null over a null, but in read-only memory. I suppose a optimiser might happen to stop this on some platforms.
Oddly enough the following (incorrect) code will (probably) not give you a seg fault, and even give the "right" answer:
char one[] = "one";
char two[] = "two";
strcat(one, two);
printf("%s\n", one);
This successfully writes "onetwo" to stdout on my machine. We get a stack scribble, which we happen to get away with.
On the other hand this does seg fault:
char* one = "one "; // Plenty of storage, but not writable.
char two[] = "two";
strcat(one,two);
Hence the solution:
const unsigned enoughSpace = 32;
char one[enoughSpace] = "one";
char two[] = "two";
strcat(one,two);
printf("%s\n", one);
The issue with this is of course, how large to make enoughSpace in order to store what ever is coming?
Hence the functions strncat, or strcat_s, or more easily std::string.
Moral of the story: in C++, just like C, you really need to know what your memory layout is.
There are several problems here. Firstly, though you have casted the strings to mutable versions, they really are string literals and hence should not be written. Secondly, you are using strcat which will write into the string buffer, completely ignoring the length of the string buffer (it's better to use strncat which requires you to specify the length of the buffer). Lastly, since this is C++, it would be way better to use:
#include <string>
// ...
string one = "one";
string two = "two";
one.append(two);
You never reserved some space for your strings.
#include <string.h>
#include <stdio.h>
int main(void){
char str[20] = "";
strcat(str, "one");
strcat(str, "two");
printf("%s", str);
}
Would be one correct way to do this. The other (and way better) is to use the std::string class.
#include <string>
#include <cstdio>
int main(void){
std::string str;
str += "one";
str += "two";
std::printf("%s", str.c_str());
}
Your destination string should be large enough to hold both the destination and the source string. So an example would be
char one[10] = "one";
char two[4] = "two";
strcat(one,two);
strcat needs a "writeable" buffer as the target. In your example, it is a pointer to a string constant (or literal), which you cannot write to, thus it results in an exception. The target buffer can be a buffer on the stack or one dynamically allocated (e.g., with malloc).
This is not the problem of "not enough space".
char *a = "str";
Look at the code above, the pointer a is point to "static memory". The string "str" is stored in the static place in the PCB, which means it can't be overwritten.
So, the codes below will be better:
#include <string>
using std::string;
string a = "stra";
string b = "strb";
a += b;
Related
This is from C++ Primer 5th edition. What do they mean by "the size of largeStr". largeStr is an instance of std::string so they have dynamic sizes?
Also I don't think the code compiles:
#include <string>
#include <cstring>
int main()
{
std::string s("test");
const char ca1[] = "apple";
std::strcpy(s, ca1);
}
Am I missing something?
strcpy and strcat only operate on C strings. The passage is confusing because it describes but does not explicitly show a manually-sized C string. In order for the second snippet to compile, largeStr must be a different variable from the one in the first snippet:
char largeStr[100];
// disastrous if we miscalculated the size of largeStr
strcpy(largeStr, ca1); // copies ca1 into largeStr
strcat(largeStr, " "); // adds a space at the end of largeStr
strcat(largeStr, ca2); // concatenates ca2 onto largeStr
As described in the second paragraph, largeStr here is an array. Arrays have fixed sizes decided at compile time, so we're forced to pick some arbitrary size like 100 that we expect to be large enough to hold the result. However, this approach is "fraught with potential for serious error" because strcpy and strcat don't enforce the size limit of 100.
Also I don't think the code compiles...
As above, change s to an array and it will compile.
#include <cstring>
int main()
{
char s[100] = "test";
const char ca1[] = "apple";
std::strcpy(s, ca1);
}
Notice that I didn't write char s[] = "test";. It's important to reserve extra space for "apple" since it's longer than "test".
You are missing the
char largeStr[100];
or similar the book doesn't mention.
What you should do is forget about strcpy and strcat and C-style strings real quick. Just remember how to make c++ std::string out of them and never look back.
char* s1;
strcpy(s1,"smilehihi");
s1[6] = 'a';
When I compile, VS do not have any errors. But in the runtime, my code makes mistake. I think I do not really understand about strcpy
The main issue here is not the strcpy() function but the fact that you don't allocate any memory for the string itself.
If I were you, I would do something like
char* s1=(char*)malloc(SIZE); // the SIZE is the predefined maximum size of your string
strcpy(s1,"smilehihi");
s1[6] = 'a';
Edit:
Just as an advice, consider using stpncpy(). It helps to avoid buffer overflow, and, in your case, will help you avoid exceeding the maximum size of char*
char * stpncpy(char * dst, const char * src, size_t len);
The problem is that you have not allocated any space for what you wish to store in s1: "smilehihi". You declare s1 as a pointer variable, but it needs something to point at. You can allocate space by using the new operator.
char* s1 = new char[stringLength + 1]; //stringLength = length of string stored
// + 1 to hold null terminator character
strcpy(s1, "smilehihi");
s1[6] = 'a';
You have to declare #define _CRT_SECURE_NO_WARNINGS at the top of your main file to avoid an error during compilation due to strcpy() being deprecated.
You need to allocate variable first by malloc() or by using the keyword new .
Also deallocate the memory at the end
At first you should allocate char* s1.
char *s1 = new char[9]; // C++ version
or you can you use C version:
char *s1 = (char*)malloc(9);
Then you can use following code:
strcpy(s1, "smilehihi");
s1[6] = 'a';
Consider these two pieces of code. They're converting base10 number to baseN number, where N is the number of characters in given alphabet. Actually, they generate permutations of letters of given alphabet. It's assumed that 1 is equal to first letter of the alphabet.
#include <iostream>
#include <string>
typedef unsigned long long ull;
using namespace std;
void conv(ull num, const string alpha, string *word){
int base=alpha.size();
*word="";
while (num) {
*word+=alpha[(num-1)%base];
num=(num-1)/base;
}
}
int main(){
ull nu;
const string alpha="abcdef";
string word;
for (nu=1;nu<=10;++nu) {
conv(nu,alpha,&word);
cout << word << endl;
}
return 0;
}
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef unsigned long long ull;
void conv(ull num, const char* alpha, char *word){
int base=strlen(alpha);
while (num) {
(*word++)=alpha[(num-1)%base];
num=(num-1)/base;
}
}
int main() {
char *a=calloc(10,sizeof(char));
const char *alpha="abcdef";
ull h;
for (h=1;h<=10;++h) {
conv(h,alpha,a);
printf("%s\n", a);
}
}
Output is the same:
a
b
c
d
aa
ba
ca
da
No, I didn't forget to reverse the strings, reversal was removed for code clarification.
For some reason speed is very important for me. I've tested the speed of executables compiled from the examples above and noticed that the one written n C++ using string is more than 10 times less fast than the one written in C using char *.
Each executable was compiled with -O2 flag of GCC. I was running tests using much bigger numbers to convert, such as 1e8 and more.
The question is: why is string less fast than char * in that case?
Your code snippets are not equivalent. *a='n' does not append to the char array. It changes the first char in the array to 'n'.
In C++, std::strings should be preferred to char arrays, because they're a lot easier to use, for example appending is done simply with the += operator.
Also they automatically manage their memory for you which char arrays don't do. That being said, std::strings are much less error prone than the manually managed char arrays.
Doing a trace of your code you get:
*a='n';
// 'n0000'
// ^
// a
++a;
// 'n0000'
// ^
// a
*a='o'
// 'no000'
// ^
// a
In the end, a points to its original address + 1, wich is o. If you print a you will get 'o'.
Anyways, what if you need 'nothing' instead of 'no'? It wont fit in 5 chars and you will need to reallocate mem etc. That kind of things is what string class do for you behind the scenes, and faster enough so it's not a problem almost every scenario.
It's possible to use both char * and string to handle some text in C++. It seems to me that string addition is much slower than pointer addition. Why does this happen?
That is because when you use a char array or deal with a pointer to it (char*) the memory is only allocated once. What you describe with "addition" is only an iteration of the pointer to the array. So its just moving of a pointer.
// Both allocate memory one time:
char test[4];
char* ptrTest = new char[4];
// This will just set the values which already exist in the array and will
// not append anything.
*(ptrTest++) = 't'
*(ptrTest++) = 'e';
*(ptrTest++) = 's';
*(ptrTest) = 't';
When you use a string instead, the += operator actually appends characters to the end of your string. In order to accomplish this, memory will be dynamically allocated every time you append something to the string. This process does take longer than just iterating a pointer.
// This will allocate space for one character on every call of the += operator
std::string test;
test += 't';
test += 'e';
test += 's';
test += 't';
std::string a(2,' ');
a[0] = 'n';
a[1] = 'o';
Change the size of your string in the constructor or use the reserve, resize methods, that is your choice.
You are mixing different things in your question, one is a raw representation of bytes that can get interpreted as a string, no semantics or checks, the other is an abstraction of a string with checks, believe me, it is a lot of more important the security and avoid segfaults that can lead on code injection and privilege escalation than 2ms.
From the std::string documentation (here) you can see, that the
basic_string& operator+=(charT c)
is equivalent to calling push_back(c) on that string, so
string a;
a+='n';
a+='o';
is equivalent to:
string a;
a.push_back('n');
a.push_back('o');
The push_back does take care of a lot more than the raw pointer operations and is thus slower. It for instance takes care of automatic memory management of the string class.
Suppose we have char *a ="Mission Impossible";
If we give cout<<*(a+1), then the output is i.
Is there any way to change this value, or this is not possible?
Yes, there are several ways to do this, but you have to make a copy of the string first because if you didn't, you'd be modifying memory you're not allowed to (where string literals are stored).
const char* a = "Mission Impossible"; // const char*, not char*, because we can't
// modify its contents
char buf[80] = {}; // create an array of chars 80 large, all initialised to 0
strncpy(buf, a, 79); // copy up to 79 characters from a to buf
cout << *(buf + 1); // prints i
buf[1] = 'b';
cout << *(buf + 1); // prints b
*(buf + 1) = 't';
cout << buf[1]; // prints t
That said, if this exercise is not for learning purposes, it is highly recommended that you learn and use std::string rather than C-style strings. They are superior in almost every way and will result in far less frustration and errors in your code.
char a[] = "Mission Impossible";
a[1] = 'x';
String literals cannot be modified. Typically they are placed a section of the binary that will be mapped read-only, therefore writing to them generates a fault. (This is implementation-defined behavior, but this happens to be the most common implementation these days.)
By declaring the string as a character array it is writable. The other alternative would be to duplicate the string literal into heap memory, either through malloc, new, or std::string.
No, the char* a is actually read-only and if you try to modify the content you will get undefined behavior. You should ideally declare a as const char*.
The simplest way to change that is doing *(a+1)='value_you_want';
This will change the content of a pointer (your case pointer is a+1) to the value you set.
I am having problems when using the strcat function in C++.
If I do :
MyClass::MyClass(char* myString){
char* AnotherString = myString;
strcat(AnotherString, "bob");
}
Then everything is fine. However, if I do:
MyClass::MyFunction(){
char* AnotherString = "fred";
strcat(AnotherString, "bob");
}
I get an unhandled exception in strcat.asm. Any ideas?
Regards
The answer you need...
is to use C++:
std::string anotherString = "fred";
anotherString += "bob";
The answer you probably want...
is what both Let_Me_Be and Moo-Juice said, combined.
This bit of code:
char* anotherString = "fred";
is extremely dangerous and should by all means be avoided. fred is stored in a read-only section of the memory and cannot be changed -- it is essentially the same as a const char* for all pratical purposes. Note that char anotherString[] = "fred"; is a whole different story, as it actually stores a copy of fred, which can be modified at will.
However, as Moo-Juice pointed out, strcat concatenates the second argument after the first one, which means the first string must have enough allocated room to hold both of them. So in your case, char anotherString[] = "fred"; would do you no good, as anotherString would only be 5 bytes long. You should then write:
char anotherString[8] = "fred"; // fred + bob + 1
strcat(anotherString, "bob");
Of course, in a real world scenario you probably don't know the string sizes in advance, so you'd use malloc to allocate an adequated buffer.
The buffer pointed to by "dest" in strcat(dest, src) must be large enough to hold the resulting string. So:
char* anotherString = "fred"; // 5 bytes including zero-terminator
e.g, no room for "Bob".
But, you've posted this in C++ so why are you using strcat() anyway?
#include <string>
std::string another = "fred";
another.append("bob");
First, the compiler shouldn't allow you to compile this (without warnings):
char* str = "fred";
The correct code is:
const char* str = "fred";
String literals are constants, therefore you can't modify their contents.