Inputting a string into dynamically allocated memory of char in c++ - c++

Is this correct or is there a better way to do this.
Visual Studio gives an error saying 'strcpy() is depreciated'.
using namespace std;
char* ptr;
ptr=(char *)calloc(1,sizeof(char));
cout << "Input the equation." << endl;
string eqn;
getline(cin, eqn);
ptr = (char *)realloc(ptr, top + eqn.size()+1);
strcpy(ptr, eqn.c_str());
P.S. I want to ptr to be the exact size of the input equation.

Assuming that what you're trying to achieve is to create a modifiable char buffer given a std::string, the better choice is to use std::vector<char> to create such a buffer.
#include <vector>
#include <string>
#include <iostream>
//...
void foo(char *x)
{
// do something to 'x'
}
using namespace std;
int main()
{
cout << "Input the equation." << endl;
string eqn;
getline(cin, eqn);
// construct vector with string
std::vector<char> ptr(eqn.begin(), eqn.end());
// add null terminator
ptr.push_back(0);
foo( &ptr[0] );
}
The above creates a modifiable, null-terminated C-string by utilizing the std::vector called ptr. Note that there are no calls to malloc, calloc, etc.

strcpy is deprecated because it's a common source of buffer overflow problems, that are generally fixed with strncpy. Having said that, you are much better off using std::string in the first place.

If you want to have a duplicate of a string with malloc, you may simply use strdup:
char* ptr = strdup(eqn.c_str());
// ..
free(ptr);

Related

How can I copy multiple char* strings into one using strcpy_s()?

Using the strcpy_s() function I want to collate the first three strings into the final one to print my full name. This is what I have and it doesn't work as I'm using char* strings and not std::strings.
#include <iostream>
using namespace std;
int main()
{
char str_first[] = "Nerf_";
char str_middle[] = " Herder";
char str_last[] = "42";
char str_fullName[35];
strcpy_s(str_fullName, (str_first + str_middle + str_last).c_str());
cout << str_fullName;
}
Any suggestions?
This should be close to what you're looking for, strictly using strcpy_s to concatenate strings together:
#include <string.h>
#include <iostream>
using namespace std;
int main()
{
char str_first[] = "Nerf_";
char str_middle[] = " Herder";
char str_last[] = "42";
char str_fullName[35];
int index = strcpy_s(str_fullName, sizeof str_fullName, str_first);
index += strcpy_s(str_fullName + index, sizeof str_fullName - index, str_middle);
index += strcpy_s(str_fullName + index, sizeof str_fullName - index, str_last);
cout << str_fullName;
}
The index variable serves a couple of purposes: (1) to provide a new index into the output str_fullName string as the string is built, and (2) subtracted from sizeof str_fullName, it "adjusts" the available buffer size as the string is built.
Caveats are that you should add overflow checking via the output from strcpy_s, and (as noted by others) there are better patterns to follow for doing this, but probably as an academic exercise there's something good to be learned here.
You need to use both strcat and strcpy
See code comments for more info.
// disable SDL warnings in Visual studio
#define _CRT_SECURE_NO_WARNINGS
#include <cstring>
#include <iostream>
using namespace std;
int main()
{
// TODO: insert checking code,
// to make sure destination can hold all characters + one termination.
char str_first[] = "Nerf_";
char str_middle[] = " Herder";
char str_last[] = "42";
char str_fullName[35];
// copy first string because we need null terminated destination
strcpy(str_fullName, str_first);
// append the rest, string is auto null terminated.
strcat(str_fullName, str_middle);
strcat(str_fullName, str_last);
cout << str_fullName;
}
If I am not mistaken the function strcpy_s expects three arguments. So either supply one more argument to the function call or use instead the function strcpy.
And there is no need to use the standard class std::string to perform the task.
The code can look the following way
strcpy( str_fullName, str_first );
strcat( str_fullName, str_middle );
strcat( str_fullName, str_last );
Or you could use strcpy_s and strcat_s provided that you will specify the correct number of arguments.
Pay attention to that you need to include the header
#include <cstring>

Use strcpy to transform a C++ string to a Char array

For some reason, I was trying to covert a C++ string to a char array. Below is what I did:
string aS="hello world";
char aC[aS.size()];
strcpy(aC, aS.c_str());
cout << aC[0] << endl;
string bS="veooci m eode owtwolwwwwtwwj mooawee mdeeme eeeec eme aemmeledmll llllleolclclcmslococecewaccocmelaeaccoaaooojutmjooooocoemoooealm omjcdmcmkemmdemmmiwecmcmteeeote eoeeeem ecc e yolc e w dtoooojttttmtwtt ttjcttoowl otdooco ko mooooo aowmemm o et jmc cmlctmmcccjcccecomatocooccoeoclooomoecwooo mcdoo dcdco dddooedoemod eddeedoedje emadleweemeeedeeeec or o m wejeetoj o ojjjlwdjjjj mjmceaeoaai laaadoaa aetmotaemmj mmmmmmlmm cmol c mwoaoe omav";
char bC[bS.size()];
strcpy(bC, bS.c_str());
cout << aC[0] << endl;
When aC[0] was first called, it gave 'h' as expected. However, when aC[0] is called at the second time, it gave ''. Could someone explain me what happened here?
For some reason, I was trying to covert a C++ string to a char array
Why don't you just use .c_str(), it does this for you
string aS="hello world";
cout << aS.c_str();
char aC[aS.size()];
would need to be:
char aC[aS.size() + 1];
in order to allow for the terminating '\0' required for a C string.
If you don't want to use the std::string::c_str() member function, you should then allocate the char array dynamically, as you cannot declare variable length arrays in C++, such as:
char* bC = new char[aS.size() + 1]; // don't forget to delete[]
strcpy(bC, bS.c_str());
I can see some utility of changing to an array if you're calling a function that will change the string buffer (pre C++11). Otherwise, use the other solutions such as c_str() if the buffer is not going to be changed.
However, if you really wanted a char array due to the buffer possibly being changed, use std::vector<char>. This will bypass the issue of using non-standard syntax (aC[aS.size()]), and removes the need to dynamically allocate memory. A std::vector<char> effectively is a changeable string buffer, only wrapped.
#include <vector>
#include <string>
#include <cstring>
#include <iostream>
using namespace std;
int main()
{
string aS="hello world";
std::vector<char> aC(aS.begin(), aS.end()); // copy
aC.push_back(0); // null-terminate
cout << &aC[0] << endl;
}
Output:
hello world
Now, where you need to specify a character array pointer, you just pass the address of the first element in the vector (provided that the vector is not empty).
Live Example: http://ideone.com/tF32Zt

Program not coutting

I am using th following code but it only asks me for a input and closes without couting my input
#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
int main(){
int balance=0;
int withdraw=0;
char* str;
cin.getline(str,10);
cout<<str;
withdraw=atoi(strtok(str," "));
balance=atoi(strtok(NULL," "));
cout<<withdraw<<" "<<balance;
return 0;
}
char* str;
This only gives you a pointer. That pointer doesn't point anywhere, especially not at some chars that you can write to. When you call cin.getline(str,10), it tries to write to where this pointer is pointing to. That gives you undefined behaviour. An easy fix for this is to make str an array of 10 chars:
char str[10];
However, I recommend that you start using std::string instead and figure out how to do strtok-like operations with a std::string. Hint: look at std::istringstream.
You need to allocate memory for str.
char *str = new char[10];
otherwise using uninitialized pointer will invoke undefined behavior. And call delete to free the allocated memory once you done with str.
delete[] str;
Instead of using char *, it is better to use std::string.

C++ passing char array to function

I would rather just use a string, but we aren't supposed to as the teacher hates them and wants us to figure out ways to avoid them. So I looked into using a struct, but we aren't that far in the book and she hates it when I skip ahead. So I was thinking of doing this:
#include <iomanip>
#include <iostream>
#include <stdio.h>
using namespace std;
void myfunc(char& );
int main()
{
char myname[12];
cout<<"enter a name ";
cin>>myname;
cout<<"myname is "<<myname;
cout<<"myname is " << myfunc(myname);
getchar();
getchar();
return 0;
}
void myfunc(char &myname1)
{
myname1 = "Billy"
}
But this doesn't work and I don't know why.
One way is to do it like this:
void myfunc(char *myname1)
{
strcpy(myname1,"Billy");
}
You will also need to change your main to:
myfunc(myname);
cout<<"myname is " << myname;
However you have to be careful not to overflow your initial buffer.
The reason why your original code doesn't work is because you can't assign strings to char pointers. Instead you must copy the string to the char*.
This line of code is wrong:
cout<<"myname is " << myfunc(myname);
myfunc() doesn't return anything, its return type is void.
Try using:
char* myfunc(char *myname1)
{
strcpy(myname1,"Billy");
return myname;
}
Or
myfunc(myname);
cout<<"myname is " << myname;
Arrays devolve into pointers when passed as parameters.
So the simple way that you want is:
char* myfunc(char* myname1)
{
return myname1;
}
If you were going to show off you can pass the array by reference.
But if you can't read ahead you will not be able to use this.
char* myfunc(char (&myname1)[12]) // Note you can only pass arrays of size 12
{ // to this function so it is limited in use.
return myname1;
}
TO make it more useful though you could template it:
template<int SIZE>
char* myfunc(char (&myname1)[SIZE])
{
return myname1;
}
myname1 = "Billy" doesn't copy a string it copies a pointer to the constant local memory containing "Billy"
Take a look at strncpy() or memcpy()
Pass it as a char* instead of a char&. You're passing a reference to a single character instead of a pointer to a character array in this code.
Also use strncpy (google it) to set the value of tr char* once you're in the function.
void myfunc(char& ); is the problem it should take in a char * and not a char reference which is what you did.
and in the function use strcpy(char * destination, char *source);

C++ char* array

When I create something like
char* t = new char[44];
t = strcpy(s,t);
then strlen(t); return some wrong results. how I can change this?
Both strcpy and strlen expect to find the special character NUL or '\0' in the array. An uninitialized array, as the one you've created, may contain anything at all, which means the behavior of your program is undefined when it is passed to strcpy as the source argument.
Assuming the goal was to copy s into t, to make the program behave as expected, try this:
#include <iostream>
#include <cstring>
int main()
{
const char* s = "test string";
char* t = new char[44];
// std::strcpy(t, s); // t is the destination, s is the source!
std::strncpy(t, s, 44); // you know the size of the target, use it
std::cout << "length of the C-string in t is " << std::strlen(t) << '\n';
delete[] t;
}
But keep in mind that in C++, strings are handled as objects of type std::string.
#include <iostream>
#include <string>
int main()
{
const std::string s = "test string";
std::string t = s;
std::cout << "length of the string in t is " << t.size() << '\n';
}
What are you trying to do? Do you want to copy from s to t? If so, the arguments to strcpy are reversed.
char* t = new char[44]; // allocate a buffer
strcpy(t,s); // populate it
Such C-style string processing is a red flag, but that's all I can say given this little information.
This code might be helpful:
char * strcpy (char * destination, const char * source);
t = strcpy(t, s);
You have to initialize the variable t
Do something like this:
char *t = new char[44];
memset(t, 0, 44);
// strlen(t) = 0
The strcpy function is described thus:
#include <string.h>
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src (including the terminating '\0' character) to the array pointed to by dest.
So, if you are trying to fill in your newly allocated array, you should be doing:
strcpy(t, s);
Not the other way around.