cannot copy string to an character array - c++

#include<iostream>
class ravi
{
private:
char a[10],char b[10];
public:
void setdata(char x[10],char y[10])
{
a = x; b = y;
}
void show()
{
std::cout << a << b;
}
};
int main()
{
ravi r;
r.setdata("text","copied");
r.show();
}
i am trying to copy the strings "text" "copied" to x and y and i am getting an error that "incompatible types in assignment from char* to char" .can someone tell me what is wrong with my code.

Strings in C++ are std::string. You are using char arrays, aka C-strings, NUL terminated strings, etc. which are harder to manipulate.
Simply by replacing the type of a and b (and a minor improvement on the arguments of setdata, you get something working, plus some useful features of string:
#include <string>
class ravi
{
std::string a;
std::string b;
public:
void setdata(const char* x, const char* y)
{
a = x;
b = y;
}
void show()
{
std::cout << a << b;
}
};
If this is possible (regarding the API of ravi), try and use std::string const& in lieu of const char*:
void setdata(std::string const& x, std::string const& y)
With C++17, you'd better use std::string_view in lieu of const char* for argument types:
void setdata(std::string_view x, std::string_view y)

Arrays do not have the copy assignment operator. So these statements
a=x;b=y;
are invalid.
You should use standard C function strcpy or strncpy declared in the header <cstring> to copy character arrays. Also string literals in C++ have types of constant character arrays. So the parameters of the member function setdata should be declared with the qualifier const.
void setdata( const char x[], const char y[] )
{
strncpy( a, x, sizeof( a ) );
a[sizeof( a ) - 1] = '\0';
strncpy( b, x, sizeof( b ) );
b[sizeof( b ) - 1] = '\0';
}
Take into account that this statement is invalid
char a[10],char b[10];
Either you should write
char a[10]; char b[10];
or
char a[10], b[10];

Use the strcpy function from string.h:
#include <string.h>
void setdata(char x[10],char y[10])
{
strcpy(a,x);
strcpy(b,y);
}

Related

How to initialize C-style char array and int array via member initialization list through constructor?

Code-1
#include <iostream>
#include <cstring>
class A
{
private:
int p[5];
char str[20];
public:
A(int *q, char *s)
{
for(int i=0; i<=4; i++)
{
p[i]=*q;
q++;
}
strcpy(str,s);
}
};
int main()
{
int r[5]={2, 3, 5, 7, 11};
char ch[]="bonaparte";
A a1(r, ch);
return 0;
}
Output ( Runs smoothly but just gives warning )
Clang-Tidy: Constructor does not initialize
these fields: p, str
Why this warning is coming. I know that I am assigning in constructor not initializing but When I create simple class which just have int type variable and If I assign that in this same way it didn't give such warning ?
Code-2
#include <iostream>
#include <cstring>
class A
{
private:
int p[5];
char str[20];
public:
A(int *q, char *s): // just not getting how we can do this initialization
{
}
};
int main()
{
int r[5]={2, 3, 5, 7, 11};
char ch[]="bonaparte";
A a1(r, ch);
return 0;
}
Is there any way to initialize int type or C-style char array via member initialization list through constructor.
I know that I can replace char array with string but I want to know a way for C-style char array.
Arrays in C++ are not the friendliest bit of the language.
Specialy not when you let them decay to pointers (size information is lost).
So I prefer to use std::array, std::vector and std::string since these standard library classes help you prevent all sort of memory bugs.
About your initialization question, yes you can only assign in the body of the constructor. This is another reason I like std::array/std::vector better you can use them in the initializer. I also consider ::strcpy to be a left over from 'C' not to be used anymore in current C++. Have fun learning more C++ :)
#include <iostream>
//#include <cstring> // <== don't use this. (If you want to use strings in C++ use <string>
#include <vector>
#include <string>
// try to learn not to use what is called
// "magic numbers" in your source code!
// define numbers you are going to use
//
const std::size_t int_array_size = 5;
const std::size_t string_array_size = 20;
// we don't know the length of the string yet, but we can let
// the compiler figure it out and we make a templated constructor
class A
{
public:
// pass arrays in by const, you're not supposed to
// change their content.
A(const int (&p)[int_array_size], const char (&str)[string_array_size])
{
// I always use std::size_t for indices in arrays (not supposed to be <0)
for (/*int*/ std::size_t i = 0; i < int_array_size; i++) m_p[i] = p[i];
// don't use ::strcpy it's not "safe". It depends on correct input
// like the string having a trailing 0
for (std::size_t i = 0; i < string_array_size; i++) m_str[i] = str[i];
}
private:
int m_p[int_array_size];
char m_str[string_array_size];
};
// this is one way I would code it.
// using C++ with variable length array (so I use std::vector, for fixed length use std::array)
class B
{
public:
B(const std::vector<int>& p, const std::string& str) :
m_p{ p },
m_str{ str }
{
}
private:
std::vector<int> m_p; // or std::array<int,int_array_size>
std::string m_str;
};
int main()
{
// I prefer to use aggregate initialization (https://en.cppreference.com/w/cpp/language/aggregate_initialization)
int r[int_array_size]{ 2, 3, 5, 7, 11 };
// The next line is defined behavior. C++ standard says all remaining
// values of ch after bonaparte will be 0
char ch[string_array_size]{ "bonaparte" };
A a1(r, ch);
B b1{ {1,2,3}, "hello world!" };
return 0;
}

initialize const char[] as non-static class member

class foo {
public:
const char name[100];
foo(const char name[]) : name(name) {};
};
int main(){
foo("test");
return 0;
}
Does not compile. How do I initialize const char[] non-static class member?
You have different option, depending on what you want to achieve.
arrays in C++ are strange beasts, they do not behave like most other types, in particular they decay to pointers and do not have copy-constructors (unless wrapped in a structure/class).
foo(const char name[]) does not take an array by value/by copy, it takes a pointer (yes, the syntax is confusing).
Thus name(name) is trying to initialize an array with a pointer.
If this would compile, it would make it super-easy to overflow the stack by accident, as there is no guarantee that the pointer name points to an array that is long at most 100 elements.
Solution 1
Use a more suitable construct - use a string.
From your snippet, it seems you want to store a piece of text (variable named name, initialisation with a string-literal...), so a std::string or other string-like class (even const char*) is a better construct.
class foo {
public:
std::string name;
explicit foo(std::string name_) : name(name_) {};
};
int main(){
foo("test");
}
Solution 2
Use a better array
If you really need to store/copy an array, consider using std::array (since c++11)
#include <array>
class foo {
public:
std::array<char, 100> name;
explicit foo(std::array<char, 100> name_) : name(name_) {};
};
int main(){
foo(std::array<char, 100>{"test"});
}
Solution 3
Pass the array by const-ref.
There are use--cases where you really want to use an array.
In this case you need to pass the value by reference, and copy the content with std::initializer_list (since c++14, but it's possible to emulate in c++11)
#include <utility>
class foo {
template <std::size_t... PACK1>
explicit foo(const char (&name_)[100], std::index_sequence<PACK1...>)
: name{ name_[PACK1]... }
{}
const char name[100];
public:
explicit foo(const char (&name_)[100])
: foo(name_, std::make_index_sequence<100>{})
{}
};
int main(){
const char hello[100] = "hello!";
foo f = foo(hello);
}
const char (&arr)[100] is an array of length 100 passed by const-reference.
As arrays do not have copy-constructors, we need to use index_sequence to initilize all members.
Solution 4
Use pointers and initialize the array in 2 phases.
Passing the array by const-reference means you need to create such a big array beforehand, and that you cannot pass a string literal which length is not exactly 101 (because of terminatig \0).
#include <cstring>
class foo {
const char name[100];
public:
// constructor requires copy... unsure if needs to be so
explicit foo(const char* name_)
{
std::copy(name_, name_ + std::strlen(name_), name);
}
};
int main(){
const char test[100] = "test!";
foo f = foo(test);
}
i would sugest to use a std::string if you are using c++, but if the const char [] is a must, here is the solution, basically you just copy some portion of the shortest string to the array of size 100, leaving unfilled the extra space(ie: name will result in name = ['t','e','s','t','\0',...]
https://www.cplusplus.com/reference/cstring/memcpy/
https://ideone.com/91nC60
#include <iostream>
class foo{
const char *name;
public:
void showme(){
std::cout<<name<<std::endl;
};
foo(const char *_name) : name(_name) {
};
};
int main(){
foo a("test");
a.showme();
return 0;
}
or
#include <iostream>
struct foo{
const char *name;
void showme(){
std::cout<<name<<std::endl;
};
};
int main(){
foo a={
.name="test"
};
a.showme();
return 0;
}

Why is member function call "ambiguous"?

Why is my overloaded member function only "ambiguous" as a char and not an int and string?
I'm trying to create a one-code path for my Char class by funneling code through an overloaded equals() function. It works fine when I use equals as an int and string but is ambiguous as a char.
class Char
{
private:
char cData;
int iData;
string sData;
public:
//Mutators:
void equals(char c);
void equals(int c);
void equals(string c);
//Constructors:
Char(char c);
Char(int c);
Char(string c);
};
void Char::equals(char c)
{
cData = c;
}
void Char::equals(int c)
{
iData = c;
}
void Char::equals(string c)
{
sData = c;
}
Char::Char(char c)
{
this->equals(c); //Call to member function 'equals' is ambiguous
}
Char::Char(int c)
{
this->equals(c);
}
Char::Char(string c)
{
this->equals(c);
}
The error only happens for char, which is confusing since string works fine. I expected it to work for all of them since that's been the case so far.
It's ambiguous because if you do
Char c(42);
The compiler does not know whether it should call the char or int constructor. Both are an equally good match.
The same goes for equals(123);. Again, both the char and int overloads match and the compiler cannot tell which one you intend to call.
you can use a single equal method to accept a char or an int. like
void euqals(unsigned int c_i);

Array of C strings, initialized with string literals

The Ghostscript interpreter API has a function
GSDLLEXPORT int GSDLLAPI gsapi_init_with_args(void *instance, int argc, char **argv)
The final argument argv is a pointer to an array of C strings, which are interpreted as command-line arguments. I obviously cannot change the signature of the function gsapi_init_with_args to take a const char ** argument instead.
If I were willing to ignore (or silence) the deprecated conversion from string constant to 'char*' warning, then I would write simply
char *gs_argv[] = {"", "-dNOPAUSE", "-dBATCH", ...};
and pass gs_argv as the final argument. But I would prefer to fix my code so that I am not relying on an external function to behave in the way I expect it to (and effectively treat gs_argv as const char**).
Is there any simple way to declare gs_argv as an array of pointers to (non-const) C strings, and initialize its elements with string literals? (That is, using a similar approach to how I can initialize a single C string: using char c_str[] = "abc".) The best I can think of is to use
const char *gs_argv0[] = {"", "-dNOPAUSE", "-dBATCH", ...};
and then copy the contents, element by element, into gs_argv.
Please note that I understand why the compiler gives this warning (and have read the answers to, among others, this question). I am asking for a solution, rather than an explanation.
You can use:
char arg1[] = "";
char arg2[] = "-dNOPAUSE";
char arg3[] = "-dBATCH";
char* gs_argv0[] = {arg1, arg2, arg3, NULL};
int argc = sizeof(gs_argv0)/sizeof(gs_argv0[0]) - 1;
gsapi_init_with_args(instance, argc, gs_argv0)
Create copies of the string literals using strdup. This is more verbose, but fixes the warning.
char* gs_argv0[NARGS];
gs_argv0[0] = strdup("");
gs_argv0[1] = strdup("-dNOPAUSE");
// ...
Note that you will also need to free the memory allocated by strdup if you want to prevent leaks.
You might also want to add a comment to your code saying why you are doing this, to make it clear for future readers.
If you can guarantee that the function will not modify the non-const parameter, then it is acceptable to use const_cast in this situation.
A C++14 solution.
#define W(x) \
(([](auto& s)->char* \
{ \
static char r[sizeof(s)]; \
strcpy (r, s); \
return r; \
})(x))
char* argv[] =
{ W("--foo=bar",
W("baz"),
nullptr
};
Since this code requires C++11, there's a lower cost C++11 solution in another answer below. I'm leaving this one for posterity.
There are pretty much two choices: ignore it and const_cast, or do the right thing. Since this is modern C++, you're supposed to have nice, RAII classes. Thus, the simplest, safest thing to do is to safely wrap such an array.
// https://github.com/KubaO/stackoverflown/tree/master/questions/args-cstrings-32484688
#include <initializer_list>
#include <type_traits>
#include <cstdlib>
#include <cassert>
#include <vector>
class Args {
struct str_vector : std::vector<char*> {
~str_vector() { for (auto str : *this) free(str); }
} m_data;
void append_copy(const char * s) {
assert(s);
auto copy = strdup(s);
if (copy) m_data.push_back(copy); else throw std::bad_alloc();
}
public:
Args(std::initializer_list<const char*> l) {
for (auto str : l) append_copy(str);
m_data.push_back(nullptr);
}
template <std::size_t N>
Args(const char * const (&l)[N]) {
for (auto str : l) append_copy(str);
m_data.push_back(nullptr);
}
/// Initializes the arguments with a null-terminated array of strings.
template<class C, typename = typename std::enable_if<std::is_same<C, char const**>::value>::type>
Args(C l) {
while (*l) append_copy(*l++);
m_data.push_back(nullptr);
}
/// Initializes the arguments with an array of strings with given number of elements.
Args(const char ** l, size_t count) {
while (count--) append_copy(*l++);
m_data.push_back(nullptr);
}
Args(Args && o) = default;
Args(const Args &) = delete;
size_t size() const { return m_data.size() - 1; }
char ** data() { return m_data.data(); }
bool operator==(const Args & o) const {
if (size() != o.size()) return false;
for (size_t i = 0; i < size(); ++i)
if (strcmp(m_data[i], o.m_data[i]) != 0) return false;
return true;
}
};
Let's see how it works:
#include <iostream>
extern "C" int gsapi_init_with_args(void*, int argc, char** argv) {
for (int i = 0; i < argc; ++i)
std::cout << "arg " << i << "=" << argv[i] << std::endl;
return 0;
}
int main()
{
Args args1 { "foo", "bar", "baz" };
const char * args2i[] { "foo", "bar", "baz", nullptr };
Args args2 { (const char **)args2i };
const char * args3i[] { "foo", "bar", "baz" };
Args args3 { args3i };
const char * const args4i[] { "foo", "bar", "baz" };
Args args4 { args4i };
const char * args5i[] { "foo", "bar", "baz" };
Args args5 { args5i, sizeof(args5i)/sizeof(args5i[0]) };
assert(args1 == args2);
assert(args2 == args3);
assert(args3 == args4);
assert(args4 == args5);
gsapi_init_with_args(nullptr, args1.size(), args1.data());
}
Output:
arg 0=foo
arg 1=bar
arg 2=baz
Try to const_cast it:
gsapi_init_with_args(instance, argc, const_cast<char**>(argv));
Maybe it will help with fixing warning.
Inspired by n.m.'s C++14 version, here's a C++11 version. The trick is to use an evaluated empty lambda expression to generate a fresh type, so that each instantiation of W__ is unique.
template <typename T, int N> static char * W__(const char (&src)[N], T) {
static char storage[N];
strcpy(storage, src);
return storage;
}
#define W(x) W__(x, []{})
char * argv[] = {
W("foo"),
W("bar")
};
The static in front of W__'s return type means that W__ has internal linkage and won't bloat the object file with extra symbols. It has nothing to do with the static in front of storage, as the latter indicates the static storage duration for the local variable. The code below would be perfectly valid, but of course doing the wrong thing and having undefined behavior:
template <typename T, int N> static char * BAD(const char (&src)[N], T) {
char storage[N];
strcpy(storage, src);
return storage;
}
Since a lambda has to be evaluated, you can't simply make its type a template argument:
template<typename> void G();
G<decltype([]{})>(); // doesn't work

C/C++: Pointers within Const Struct

How do I force const-ness of the memory pointed to by obj->val1 in the function fn?
#include <iostream>
struct foo {
int* val1;
int* val2;
int* val3;
};
void fn( const foo* obj )
{
// I don't want to be able to change the integer that val1 points to
//obj->val1 = new int[20]; // I can't change the pointer,
*(obj->val1) = 20; // But I can change the memory it points to...
}
int main(int argc, char* argv[])
{
// I need to be able to set foo and pass its value in as const into a function
foo stoben;
stoben.val1 = new int;
*(stoben.val1) = 0;
std::cout << *(stoben.val1) << std::endl; // Output is "0"
fn( &stoben );
std::cout << *(stoben.val1) << std::endl; // Output is "20"
delete stoben.val1;
return 0;
}
The code here is pretty self explanitory. I need to be able to make a non-const object and fill it with data, but then pass it to a function where this data cannot be modified. How can I go about this?
I know I can just pass in a const int pointer, but theoretically, this class contains several other pointers which I will need in "fn" as well.
Thanks,
Griff
Since you tagged as C++, you could make the member private and make an accessor that returns a const int *. You could originally set the member via your constructor or a friend function.
I'm not a C++ person, but in C, I'd handle this through two different struct declarations, one public, one private:
#include <stdio.h>
#include <stdlib.h>
struct private_foo {
int* val1;
int* val2;
int* val3;
};
struct public_foo {
int const * const val1;
int const * const val2;
int const * const val3;
};
void fn( struct public_foo * obj )
{
int local;
*(obj->val1) = 20; // compile error
obj->val1 = &local; // compile error
}
int main(int argc, char* argv[])
{
// I need to be able to set foo and pass its value in as const into a function
struct private_foo stoben;
stoben.val1 = malloc(sizeof(int));
if (!stoben.val1) { return -1; }
*(stoben.val1) = 0;
printf("%d", *(stoben.val1) );
fn( (struct public_foo *) &stoben );
printf("%d", *(stoben.val1) );
free(stoben.val1);
return 0;
}
When I try to compile the above w/ GCC, I get the following compiler errors, since I'm trying to modify read-only memory:
temp.c: In function ‘fn’:
temp.c:20: error: assignment of read-only location
temp.c:21: error: assignment of read-only member ‘val1’
You really can't. A const foo specifies that the members inside are const, that is, they are constant pointers to integers, not pointers to constant integers.
The proper solution to this would be via encapsulation, hiding these members and providing a public interface. A practical solution, should you be forbidden to modify the struct foo, would be through private inheritance:
struct foo {
int* val1;
int* val2;
int* val3;
};
struct constFoo : private foo {
public:
const int* getVal1() { return val1; }
const int* getVal2() { return val2; }
const int* getVal3() { return val3; }
};
Of course, you would need to create the appropriate constructors, etc., so that the original foo can be set up.