I'm trying to concatenate two dynamic c arrays (containing strings) using pointers. I looked up a bunch of things online that use strcat, but I need to learn how to use pointers to do this. I'm not exactly clear on what a dynamic c array is anyway, I just know I have to use "new" for it. Here's my current code that won't compile:
#include <iostream>
using namespace std;
#define MAX_CHAR 50
void append(char*, char*);
int main()
{
char *str1 = new char[MAX_CHAR];
char *add1 = new char[MAX_CHAR];
str1 = "This string";
add1 = " add this one";
append(str1, add1);
cout << str1;
delete [] add1;
delete [] str1;
return 0;
}
void append(char *str, char *add)
{
while(*str != '\0')
str++;
while(*add != '\0')
{
*str = *add;
add++;
str++;
}
*str = '\0';
}
This part doesn't do what you think it does:
str1 = "This string";
add1 = " add this one";
You're attempting to assign a string literal ("This string") to a string pointer (str1). That won't work because:
you've basically thrown away the pointers that you just allocated with new one line ago and
string literals cannot be modified during run time (literals are of type const char [], so you should expect a compiler error/warning about this).
Hence, you're going to need to manually copy the string literal into your char array. You can use the standard library function strcpy for this (this requires <cstring>):
std::strcpy(str1, "This string");
std::strcpy(add1, " add this one");
Related
I've been reading a book for self study (http://www.amazon.com/gp/product/0321992784) and I'm on chapter 17 doing the exercises. One of them I solved, but I'm not satisfied and would like some help. Thank you in advanced.
The Exercise: Write a program that reads characters from cin into an array that you allocate on the free store. Read indvidual characters until an exclamation mark(!) is entered. Do not use std::string. Do not worry about memory exhaustion.
What I did:
char* append(const char* str, char ch); // Add a character to the string and return a duplicate
char* loadCstr(); // Read characters from cin into an array of characters
int main()
{
char* str{ loadCstr() };
std::cout << str << '\n';
return 0;
}
I made 2 functions, 1 to create a new string with a size 1 larger than the old and add a character at the end.
char* append(const char* str, char ch)
/*
Create a new string with a size 1 greater than the old
insert old string into new
add character into new string
*/
{
char* newstr{ nullptr };
int i{ 0 };
if (str)
newstr = new char [ sizeof(str) + 2 ];
else
newstr = new char [ 2 ];
if(str)
while (str [ i ] != '\0')
newstr [ i ] = str [ i++ ]; // Put character into new string, then increment the index
newstr [ i++ ] = ch; // Add character and increment the index
newstr [ i ] = '\0'; // Trailing 0
return newstr;
}
This is the function for the exercise using the append function I created, It works, but from what I understand each time I call append, there is a memory leak because I create a new character array and didn't delete the old.
char* loadCstr()
/*
get a character from cin, append it to str until !
*/
{
char* str{ nullptr };
for (char ch; std::cin >> ch && ch != '!';)
str = append(str, ch);
return str;
}
I tried adding another pointer to hold the old array and delete it after making a new one, but after about 6 calls in this loop I get a runtime error that I think tells me I'm deleting something I shouldn't? which is where I got confused.
This is the old one that doesn't work beyond 6 characters:
char* loadCstr()
/*
get a character from cin, append it to str until !
*/
{
char* str{ nullptr };
for (char ch; std::cin >> ch && ch != '!';) {
char* temp{ append(str, ch) };
if (str)
delete str;
str = temp;
}
return str;
}
So I want to know how I can fix this function so there are no memory leaks. Thank you again. (Also please note, I do know these functions already exist and using std::string handles all the free store stuff for me, I just want to understand it and this is a learning exercise.)
You have to use standard C function std::strlen instead of the sizeof operator because in case of your function the sizeof operator returns the size of pointer instead of the length of the string.
Also you need to delete already allocated array.
The function can look the following way
char* append(const char* str, char ch)
/*
Create a new string with a size 1 greater than the old
insert old string into new
add character into new string
*/
{
size_t n = 0;
if ( str ) n = std::strlen( str );
char *newstr = new char[ n + 2 ];
for ( size_t i = 0; i < n; i++ ) newstr[i] = str[i];
delete [] str;
newstr[n] = ch;
newstr[n+1] = '\0';
return newstr;
}
And in the function loadCstr it can be called like
str = append( str, ch );
Also instead of the loop to copy the string you could use standard algorithm std::copy
Is the point to learn about memory management, or about how string operations work internally?
For the second (learning about string operations), you should use std::unique_ptr<char[]> which will automatically free the attached array when the pointer dies. You'll still need to calculate string length, copy between strings, append -- all the things you are doing now. But std::unique_ptr<char[]> will handle the deallocation.
For the first case, you're better off writing an RAII class (custom version of std::unique_ptr<T>) and learning how to free memory in a destructor, than scattering delete [] statements all over your code. Writing delete [] everywhere is actually a bad habit, learning it will move your ability to program C++ backwards.
I have built my own functions of strlen and strdup.
When i use my strdup in the first time it's okay, i close the window, run it again, then in the end of the program after the return 0 from the main the program crashes. VS just says that it triggered a breakpoint.
#include "stdafx.h"
#include <iostream>
using namespace std;
int MyStrlen(const char* str);
char* MyStrdup(const char* str);
int main()
{
char *s1 = "Hello World!";
char *s2 = MyStrdup(s1);
cout << s1 << " , " << s2 << endl;
system("pause");
return 0;
}
int MyStrlen(const char* str)
{
register int iLength = 0;
while (str[iLength] != NULL)
{
iLength++;
}
return iLength;
}
char* MyStrdup(const char* str)
{
char* newStr;
int strLength = MyStrlen(str);
newStr = new char(strLength+1);
for (register int i = 0; i < strLength; i++)
{
newStr[i] = str[i];
}
newStr[strLength] = NULL;
return newStr;
}
Can someone note the place that makes it crash? I think it's a memory leak maybe.
Also, can you note things to improve in the code? For my learning purpose
EDIT: Thanks, I don't know why I used () instead of [] to define my new char[]. That was a memory leak or overwrite after all.
The "new" statement for an array should be with square brackets:
newStr = new char[strLength+1];
When you do
new char(c)
It allocates a single character and copies the character c into it.
When you do
new char[n]
it allocates memory for n characters
The expression new char(strLength+1) allocates a single character, and initializes it to strLength + 1. That of course means you will write out of bounds and have undefined behavior when you copy the string.
You should use new char[strLength + 1] instead, to allocate an "array" of characters.
On an unrelated note, while the terminating character in a string is commonly called the null character, it's not actually a null pointer (which is what NULL is for). Not that it really matters since in C++ NULL is a macro that expands to 0, but you should probably be explicit and use '\0' anyway (it gives more context for future readers).
I would like to convert string to char array but not char*. I know how to convert string to char* (by using malloc or the way I posted it in my code) - but that's not what I want. I simply want to convert string to char[size] array. Is it possible?
#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
int main()
{
// char to string
char tab[4];
tab[0] = 'c';
tab[1] = 'a';
tab[2] = 't';
tab[3] = '\0';
string tmp(tab);
cout << tmp << "\n";
// string to char* - but thats not what I want
char *c = const_cast<char*>(tmp.c_str());
cout << c << "\n";
//string to char
char tab2[1024];
// ?
return 0;
}
Simplest way I can think of doing it is:
string temp = "cat";
char tab2[1024];
strcpy(tab2, temp.c_str());
For safety, you might prefer:
string temp = "cat";
char tab2[1024];
strncpy(tab2, temp.c_str(), sizeof(tab2));
tab2[sizeof(tab2) - 1] = 0;
or could be in this fashion:
string temp = "cat";
char * tab2 = new char [temp.length()+1];
strcpy (tab2, temp.c_str());
Ok, i am shocked that no one really gave a good answer, now my turn. There are two cases;
A constant char array is good enough for you so you go with,
const char *array = tmp.c_str();
Or you need to modify the char array so constant is not ok, then just go with this
char *array = &tmp[0];
Both of them are just assignment operations and most of the time that is just what you need, if you really need a new copy then follow other fellows answers.
str.copy(cstr, str.length()+1); // since C++11
cstr[str.copy(cstr, str.length())] = '\0'; // before C++11
cstr[str.copy(cstr, sizeof(cstr)-1)] = '\0'; // before C++11 (safe)
It's a better practice to avoid C in C++, so std::string::copy should be the choice instead of strcpy.
Easiest way to do it would be this
std::string myWord = "myWord";
char myArray[myWord.size()+1];//as 1 char space for null is also required
strcpy(myArray, myWord.c_str());
Just copy the string into the array with strcpy.
Try this way it should be work.
string line="hello world";
char * data = new char[line.size() + 1];
copy(line.begin(), line.end(), data);
data[line.size()] = '\0';
Try strcpy(), but as Fred said, this is C++, not C
You could use strcpy(), like so:
strcpy(tab2, tmp.c_str());
Watch out for buffer overflow.
If you don't know the size of the string beforehand, you can dynamically allocate an array:
auto tab2 = std::make_unique<char[]>(temp.size() + 1);
std::strcpy(tab2.get(), temp.c_str());
If you're using C++11 or above, I'd suggest using std::snprintf over std::strcpy or std::strncpy because of its safety (i.e., you determine how many characters can be written to your buffer) and because it null-terminates the string for you (so you don't have to worry about it). It would be like this:
#include <string>
#include <cstdio>
std::string tmp = "cat";
char tab2[1024];
std::snprintf(tab2, sizeof(tab2), "%s", tmp.c_str());
In C++17, you have this alternative:
#include <string>
#include <cstdio>
#include <iterator>
std::string tmp = "cat";
char tab2[1024];
std::snprintf(tab2, std::size(tab2), "%s", tmp.c_str());
Well I know this maybe rather dumb than and simple, but I think it should work:
string n;
cin>> n;
char b[200];
for (int i = 0; i < sizeof(n); i++)
{
b[i] = n[i];
cout<< b[i]<< " ";
}
I am trying to reverse a null terminated string in place in C++. I have written the code below:
//Implement a function to reverse a null terminated string
#include<iostream>
#include<cstdlib>
using namespace std;
void reverseString(char *str)
{
int length=0;
char *end = str;
while(*end != '\0')
{
length++;
end++;
}
cout<<"length : "<<length<<endl;
end--;
while(str < end)
{
char temp = *str;
*str++ = *end;
*end-- = temp;
}
}
int main(void)
{
char *str = "hello world";
reverseString(str);
cout<<"Reversed string : "<<str<<endl;
}
However, when I run this C++ program , I get a a write access violation inside the while loop at the statement : *str = *end ;
Even though this is fairly simple, I can't seem to figure out the exact reason I am getting this error.
Could you please help me identify the error?
char *str = "hello world";
is a pointer to a string literal, and can't be modified. String literals reside in read-only memory and attempting to modify them results in undefined behavior. In your case, a crash.
Since this is clearly an assignment, I won't suggest using std::string instead, since it's good to learn these things. Use:
char str[] = "hello world";
and it should work. In this case, str would be an automatic-storage (stack) variable.
void reverse (char s[]){
int len = strlen(s);
int j = len - 1;
for (int i = 0; i < j; i++,j--){
cout << s[i];
char ch = s[i];
s[i] = s[j]; //error line - giving exception, cannot write to the memory
s[j] = ch;
}
}
I am using Visual Studion 2008 and i can't understand whats the problem here .. :s .. I am out of C++ practice :$ .
The problem is that it uses C-style strings instead of C++ style strings. In particular, you are apparently trying to write to a constant string literal:
char const* str = "I cannot be written to";
C++ allows to omit the const here for backwards compatibility but the literal is still constant.
Finally, C++ already has a reverse function:
#include <algorithm>
#include <iostream>
#include <string>
int main() {
std::string str = "Hello world";
std::reverse(str.begin(), str.end());
std::cout << str << std::endl;
}
I'd guess the problem is with how you're calling it, probably with a string literal, something like:
reverse("This is a string");
or:
char *string = "This is a string";
reverse(string);
or some other minor variation. In any case, you're trying to write to a string literal, which gives undefined behavior.
Since you're apparently using C++, I'd consider using an std::string instead:
void reverse(std::string &s) {
int j=s.length()-1;
for (int i=0; i<j; i++, j--) {
// ..
}
}
Are you calling this on a const char* or a string literal?
Are you trying to reverse
reverse("foo");
or
char *s = "foo";
reverse(s);
You'll need to create a new string from the non-writeable one and reverse that instead. You can use strdup.
char *s = strdup("foo");
reverse(s);
free(s, strlen(s));
Also note that your question is tagged c++, so you should probably be using std::string.