I'm sure this is an easy question for most but I'm having trouble trying to figure out why I can't manipulate this sting and better yet how I should go about doing it. So for example we have:
char *str1="Hello World";
All I want to do is manipulate the string that is being pointed to by 'str1'. For example, as shown below, I could output the string and see the original. Then I could add a null character in there and shorten it.
cout << str1 << '\n';
str1[5] = '\0';
cout << str1;
I've also tried:
cout << str1 << '\n';
*(str1+4) = '\0';
cout << str1;
Either way I'm hoping to see something like this:
Hello World
Hello
The error I'm getting in both cases is when I try to alter the string. I know it would be easier to just declare str1 as an array (char str1[] = ....) but I'm given the constraint of having to use the dreaded char *
String literals are stored in read-only memory. You cannot modify them. In fact, in modern C++, attempting to initialise str1 the way you did will give an error. It should be a const char*:
const char* str1 = "Hello World";
This makes it clear that you shouldn't be modifying the chars.
If you want a copy of the string that you can manipulate, you should make str1 an array:
char str1[] = "Hello World";
When you initialise an array with a string literal, the characters are copied into the array.
So after all of the help I've received from you all I went with first determining the length of the strings, initializing an array of the same size+1, and then iterating through the original to save it into an array. Then I was able to manipulate it as i pleased.
int someFunc(char *inpStr){
int counter = 0;
//Find the length of the input string
while(inpStr[counter]!='\0'){counter++;}
//Input initialize an array of same size
char strArray[counter+1];
//Copy whats in the char * to the array and make sure it ends with null
for(int i=0;i<=counter;i++){strArray[i]=*(inpStr+i);}
strArray[counter]='\0';
.....
return 0;
}
Thanks for all the help!
Why you cannot change the str1 has been explained aptly by Joseph. But still if you want to modify it you can use something like this:
char *str = "hello";
char *ptr = new char[strlen(str)+1];
strcpy(ptr,str);
ptr[2] = 'd';
str = ptr;
I hope this solves your problem.
Related
I just started learning c++, andI have problems with uderstanding working on adresses and rewriting variables from one adress to another.
I have a program to correct:
using namespace std;
void cp(char* str2, char* str1) {
cout << &(str1+1);
}
int main()
{
char *str1 = "ppC";
char str2[10] = "Witaj";
// cout << str2 << endl; // Witaj
cp(str2,str1);
}
Problem:
I have to write a function to rewrite text from str1 to str2.I also have to use specified amount of memory to store the text in str2.
But I've got stucked at first step:
I would like to begin with taking the adress of str1 (its adress of str1[0] am i right?) then i would like to go in loop fro after adding +1 to each adress to go through all elements of str1 and write it to new char* var and return it.
As I have understood you are going to write a function that copies a string stored in one character array in another character array.
Usuaaly such string functions also returns pointer to the first character of the destination array.
So instead of
void cp(char* str2, char* str1);
It is better to declare the function like
char * cp( char *str2, const char *str1 );
It is a low level function and t should not check whether there is enough space in the destination array. It is a problem of the caller.
So the function can be defined like
char * cp( char *str2, const char *str1 )
{
char *p = str2;
while ( *str2++ = *str1++ );
return p;
}
Take into account that the second parameter has type const char *. In this case you can use constant arrays as an argument for this parameter including string literals.
Using the variable declarations in your program you could call the function the following way
std::cout << cp( str2, str1 ) << std::endl;
I have a problem, do not to compile this code but, to execute this program. When I run it in the terminal it prints the first 2 cout then the program stops working and the screen on the windows that tells you, i think the problem is to strcat.
I'm using DEVC++ and I have windows 7 pro.
#include <iostream>
#include <string>
#include <cstdlib>
#include <string.h>
using namespace std;
int main() {
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
cout << "*c: " << *c << endl;
cout << "*cambia: " << *cambia << endl;
strcat( *cambia, *c );
cout << "*cambia: " << *cambia << endl;
}
You don't use strcat() in C++ if you don't absolutely have to (e.g. when maintaining legacy code and touching as little stuff as possible).
Use std::string and its member functions like find or substr for simple tasks, string streams or Boost libraries for more complex string splitting.
At any rate, stay away from strcat().
The method strcat() adds the string from the second argument to the buffer of which you submit to the first argument.
First, the buffer has to be writable. In your example, you are passing a string literal as buffer. Naturally, string literals are read-only. But even then, the string literal has no spare space where the new string could be added.
Instead of fixing your code, let me show you some proper examples how to concat strings in C++ and in C.
This example is showing you how to concat two C++ strings:
#include <iostream>
#include <string>
int main(int argc, const char * argv[])
{
// Create a new C++ string with an initial text.
std::string result = "First string part ";
std::cout << "Result: " << result << std::endl;
// Add some text
std::string textToAppend = "and the second part";
result.append(textToAppend);
std::cout << "Result: " << result << std::endl;
return 0;
}
The following example is showing you how to concat two strings in C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, const char * argv[])
{
// The two texts to concat
const char *firstText = "This is the first text ";
const char *secondText = "and this is the second one";
// A buffer which is large enough for the operation.
const int bufferSize = 1024;
char buffer[bufferSize];
// Copy the initial text into the buffer.
strncpy(buffer, firstText, bufferSize);
// Add the secon string
strncat(buffer, secondText, bufferSize-strlen(buffer));
// Output the string
printf("Result: %s\n", buffer);
return 0;
}
I suggest, you should use C++ strings if possible. They automatically manage the memory which prevent many memory related issues with C strings.
This line
char* cambia[] = {"ciao "};
creates a variable named cambia in a dynamically created part of memory, called 'stack'. The variable is an array with no declared size, and elements of that array are pointers to characters.
The size of the array follows from the initializer
{"ciao "}
which implies the array will have only one element, and that element is initialized with a value pointing at the first character of string "ciao ". However, the string "ciao " is placed in some completely different area of memory - it is in static block, initialized by a compiler with values found in the program's code. Compiler does not know how you use these values, in particular it doesn't know you will extend it with strcat, so it will not reserve any additional space after the string.
As a result when you concatenate "mondo" to "ciao ", you overwrite some data in memory, possibly some important data...
I'd suggest you to declare local variables for your string, with explicit size:
char cambia[ 20] = "ciao ";
char c[] = "mondo";
This will make a cambia variable long enough to keep 19-character string (plus implicit terminating zero byte '\0', ASCII NUL) and initialize its first 6 bytes with letters 'c', 'i', 'a', 'o', a space ' ' and NUL. Variable c is implicitly sized to 6 (the initializing string length 5 plus 1 for terminating NUL).
Then you can safely concatenate
strcat( cambia, c);
to obtain 11-character string "ciao mondo" and print it out
cout <<"cambia: "<<cambia<<endl;
The problem here is that you are trying to write to a read-only string storage.
These declarations:
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
declare two arrays, each with a constant string member. The "ciao " and "mondo" are located in read-only memory.
So when you call strcat(*cambia, *c), you are trying to write "mondo" onto the end of "ciao ". Not only does this write to read-only memory, but it also writes outside the memory space given for the string - there is only space for 6 char in the "ciao " string, and you are trying to add another 5 to the end of that.
The solution is to reserve some space for each string. There are various ways to do this. Here's a simple one:
char acambia[20] = "ciao "; // Space for 20 characters.
char* cambia[] = { acambia };
Of coruse, not using the extra level of indirection would make it simpler:
char cambia[20] = "ciao ";
char c[] = "mondo";
strcat(cambia, c);
would achieve the correct result.
First of all you need not headers
#include <string>
#include <cstdlib>
because neither declaration from them is used.
Aslo header
#include <string.h>
should be substituted for
#include <cstring>
In these statements
char* cambia[] = {"ciao "};
char* c[] = {"mondo"};
you defined two arrays each of them having one element of type const char *. The compiler should issue either an error or a warning because these definitions are not correct. It would be correctly to define the arrays the following way
const char* cambia[] = {"ciao "};
const char* c[] = {"mondo"};
These two statements define arrays of const pointers to string literals. It is undefined behaviour if there ia an attempt to change a string literal in a program. Programs are allowed to place string literals in a read-only memory.
You are right saying that the main problem is in statement
strcat( *cambia, *c );
Function strcat appends one character array to the end of another character array. So the second cjaracter array must reserve enough memory that accomodates the appended character array. If you even would define correctly array cambia as
char cambia[] = {"ciao "};
it had no enough memory to store also characters of array c.
So before using strcat you need to reserve enough memory where the concatenated result array would be placed.
You could do this for example the following way
char s[11];
strcpy( s, *cambia );
strcat( s, c );
cout << "s: " << s << endl;
Take into account that instead of character arrays you could use objects of standard class std::string
In this case to append one string to another is made very simply. For example
std::string cambia = "ciao ";
std::string c = "mondo";
cambia += c;
Or
cambia.append( c );
So given:
struct MemoryStruct {
char *memory;
size_t size;
};
char* memory holds a curl return, XML doc.
I am doing:
if(chunk.memory) {
std::cout << "char size is " << sizeof(chunk.memory) << std::endl;
std::string s = "";
for (int c = 0; c<sizeof(chunk.memory); c++) {
s.push_back(chunk.memory[c]);
}
std::cout << "s: " << s.c_str() << std::endl;
}
I am only getting back <?xm
So sizeof() I think is return the total bytes in the char*
How do I get what the actual value is a char*. So basically the whole curl return. Which is 5 lines of XML?
sizeof(chunk.memory) will give always you size of a pointer which in your case seems to be 4. That's why you see only 4 characters in your std::string.
If your curl return or whatever else is terminated by \0, then you can directly do the following
std::string s(chunk.memory);
If your char * is not terminated by \0, then you need to know the length of the string - you cannot use sizeof(chunk.memory) for this. If your chunk.size contains the correct size, then you can use
std::string s(chunk.memory, chunk.size);
std::string constructor can accept char* and data length (see the docs); Example:
std::string s(chunk.memory, chunk.size);
So container will pre-allocate need space for your string and initialize with it.
In MemoryStruct memory is the pointer to the first returned character and size is the number of characters returned. You want to initialize a string with this data so you will need to do:
s.assign(chunk.memory, chunk.size);
So i have a char *. And i want to cut off some bit at the end. So
char *sentence = "My name is Ted";
How do I cut off the Ted. I could make it a string and then use substring (coming from Java thats my go to method) but id rather not do that way. But im not sure how to do it with a char *.
EDIT: Further on the problem. The issue is in a function that takes a process and is meant to return the location when that process is started from. Thats fine i can get that. But the parameter char *procLocation is passed by reference so the location will be sent back there.
I can only get the location that includes the name of the process. I want to cut off the name of the process and just return the location. Ive tried making the location a string and doing a substring (string - length of the processName). Thats fine. But
procLocation = location.c_str(); // where location.substr is the location - the process name
gives back an error: error C2440: '=' : cannot convert from 'const char *' to 'char *'
Since that is a string literal, you can't modify it.
If you did:
char sentence[] = "My name is Ted";
You could simply set the character before Ted to \0.
You might be better off using std::string though.
Instead of cutting off your literal, you could use std::string constructor that copies fewer characters than is available in your char*:
const char *data = "Hello, Ted!";
string s(data, data+8);
cout << s << endl;
This prints Hello, T
This approach is less wasteful than making a std::string and taking a substring.
To your original problem, as you're coming from Java, you should (should, in the sense of RFC2119) definitely use std::string:
#include <string>
#include <iostream>
using namespace std;
int main(int argc, const char** argv) {
// copy c-string to std::string
string arg0 = argv[0];
cout << arg0 << endl;
// find last occurrence of path separator
size_t found = arg0.find_last_of("/\\");
// split off filename part of string
cout << arg0.substr(0,found) << endl;
return 0;
}
Further, you should not (should not, in the sense of RFC2119) declare the char array as a char pointer, but as a char array:
char[] s0 = "Hello World!"; // <-- is better
char * s1 = "Hello World!"; // <-- avoid this
See this post for actual reasons why this is better. It also gives the reasons for why not to modify such rvalue strings.
You've tagged the question 'c++' and 'string' but you say you don't want to do this with string and substr ? Not sure why that is. You should prefer these over char* and C style string manipulation functions wherever possible.
To do it the C++ way:
string sentence = "My name is Ted";
cout << "\"" << sentence.substr(0, sentence.rfind(' ') ) << "\"" << endl;
Although you could (modifying your code slightly so that you have a mutable string) do this in C:
char sentence[] = "My name is Ted";
*strrchr(sentence, ' ') = '\0';
printf("\"%s\"\n", sentence);
I am writing a program that needs to take text input, and modify individual characters. I am doing this by using an array of characters, like so:
char s[] = "test";
s[0] = '1';
cout << s;
(Returns: "1est")
But if I try and use a variable, like so:
string msg1 = "test";
char s2[] = msg1;
s2[0] = '1';
cout << s1[0]
I get an error: error: initializer fails to determine size of 's2'
Why does this happen?
C-style arrays require literal values for initialization. Why use C-style arrays at all? Why not just use std::string...
string msg1 = "test";
string s2 = msg1;
s2[0] = '1';
cout << s2[0];
The space for all the variables is allocated at compile time. You're asking the compiler to allocate space for an array of chars called s2, but not telling it how long to make it.
The way to do it is to declare a pointer to char and dynamically allocate it:
char *s2;
s2 = malloc(1+msg1.length()); // don't forget to free!!!!
s2 = msg1; // I forget if the string class can implicitly be converted to char*
s2[0] = '1'
...
free(s2);
I think char a[] can't be initialized by a string.
Edit: "a string" is actually a c-type string (char array with '\0' at the end).
$8.5.1 and $8.5.2 talk about rules related to initialization of aggregates.