I need to convert char array of C into string c++ but the char array is an element of struct.
Code:
This is my Structure in C
typedef struct myStruct
{
char name[50];
char abc[50];
ESL_BOOL status;
}MyStruct;
and I want to access name[50] in c++ but for that I have to convert it into string.
I have tried strcpy and memcpy.
I am using ESL_BOOL status; and it is working but confused with name[50].
The first thing you should change in the class name in your struct because that will likely cause problems because it is a keyword in C++.
Then for converting a C string into a C++ one, you can simply use the std::string constructor that accepts C-style strings.
std::string myCppString(MyStruct.name);
typedef struct myStruct {
char name[50];
char mclass[50];
ESL_BOOL status;
} MyStruct;
class is a reserved keyword of the C++ language. If you try to use it, tokenizer will take it as a keyword and cause problems later in the parsing phase, as an identifier will be expected.
It was once considered a good practice to precede all of the struct´s members with m or m_ to avoid such collisions.
To your problem: just the default "from C string" string (const char* s) constructor should be enough.
MyStruct obj;
std::string objsName(obj.name);
std::string objsClass(obj.mclass);
Related
class Student {
public:
string name;
};
vs
class Student {
public:
char* name;
};
Please correct me if I'm wrong. If we were to use char* instead of string, we will have to write our very own copy-constructor because we need to every time we have pointer variables as data members. Right?
So, my question is: Why use char* at all?
Using string, in the constructor, we can directly do:
Student(string s) {
name = s;
}
which is simpler compared to char*, which needs:
Student(string s) {
name = new char[strlen(s)+1]; // extra 1 to store the '\n'
strcpy(name,s);
}
Why not use string at all times instead of char* when being used as a data member of a class?
I think the only reason char* is used in C++ as a string is because of C. I'm sure if it was a new language, one which didn't strive to be compatible with C, char* would not be used like that. You will notice that functions that handle char* as if it were a string all come from C.
Note that in C, there is no string, so
struct Student { char* name; };
is perfectly valid C code, whereas
struct Student { string name; };
is not. Therefore, it is not unusual, when dealing with code which previously target C, to see those char* types.
There are usually little reason for using char* as a string, unless you are either writing a new string class, interfacing C functions, or dealing with legacy code.
You use char * instead of string, because a string is a string and a char * is a pointer to a character-aligned address.
Expanding on that, a string is an abstraction of a vector of characters with defined semantics. In C land, and in a lot of C++ programs, it represents an allocated block of memory along with a guarantee that it's terminated with the ascii NUL character 0x00. But a C++ implementation of string could instead use, say, a Pascal string with associated length, or it could represent strings in a string pool as a linked list.
A char * isn't providing that guarantee at all, and in fact might not be a string -- for example, it might be a collection of data with embedded 0x00 values. All it promises is that it's an address of something that the underlying architecture thinks is a character.
If you need a string, use std::string, not char*.
An obvious exception is interfacing to legacy code that uses char* to represent strings. Still, don't use char* outside of the interface layer.
You need to use char* when your data isn't a string, but a raw unstructured array of bytes. This is the case when you read or write binary data from files or network interfaces.
Sometimes, it is simpler to use char* instead of string, for example, when you are dealing with network and you need to transform a string full of bytes into a integer, float, etc.. I think that it's simpler to use a char*, instead of a string :
Using a char*
char* buffer[4];
read(buffer, 4); // A random read operation
int value = *((int*)(&buffer[0]); // Not sure if it was like that...
Using a string
std::string buffer;
buffer.resize(4);
read(buffer.data(), 4); // Will not work as buffer.data() returns a const char*
int value = *((int*)(&buffer.data()[0]));
The problem of string is that it's designed to prevent bad usage or strange manipulations. As someone said, it's also because C++ is inherited from C. So there is functions (from libc/glibc) which takes a char* and not a string.
EDIT
Even if char* is different from char**, it's pretty complex to build a bi-dimensional array using std::vector or std::string, you should either make your proper class, use char**, or library specific implementation (Boost, Maths libs, etc...)
About the only place where a competent C++ programmer will use char* is in the interface of an extern "C" program, or in very low level code, like an implementation of malloc (where you need to add a number of bytes to a void*). Even when calling into a C ABI, the char* needed by the interface will generally come from a &s[0], where s is an std::string, or if the interface is not const aware (and a lot of C interfaces aren't), then the results of a const_cast.
char const* is a bit more frequent: a string literal is, after all, a char const[], and I will occasionally define something like:
struct S
{
int value;
char const* name;
};
But only for static data, eg:
S const table[] =
{
{ 1, "one" },
{ 2, "two" },
// ...
};
This can be used to avoid order of initialization issues; in the above, the initialization is static, and guaranteed to take place before any dynamic initialization.
There are few other cases: I've used char const*, for example, when marshalling between to C ABIs. But they are rare.
So I have this defined:
static char randomstring[128];
Now whenever I mention it somewhere like so:
char *x = randomstring;
It goes fine but whenever I try to do something with its content:
char *x = ranomstring.front();
It doesn't work at all and says expression must have class type..
This problem occurs a LOT for me.
I should also mention I'm a total noob at c++.
You should probably learn the difference betwenn std::string (a class) and c-style string (char* or char[] - array).
//this calls std::string constructor to convert c-style string to std::string:
string mystring = "hello world!";
//std::string has front()
char* front = mystring.front();
//this is old-style string
char oldstring[] = "hello again!";
//you can access it as pointer, not as class
char* first = oldstring;
//but you can iterate both
for(char c : mystring) cout << c;
for(char c : oldstring) cout << c;
//...because it uses std::begin which is specialized for arrays
Arrays in C++ are not classes. They are aggregates. So they have no methods.
Use instead either standard container std::string or standard container std::vector that can dynamically change their sizes and have method front.
For example
#include <string>
//...
std::string randomstring;
//filling the string
char x = randomstring.front();
Change char *x = ranomstring.front();
To char *x = ((string)ranomstring).front();
What is the difference between the line that does not compile and the line that does compile?
The line that does not compile gives this warning: deprecated conversion from string constant to 'char*'
Also, I'm aware casting (char *) on the string being passed in to the function would solve the problem, but I would like to understand why that's even necessary when the 2nd line compiles just fine.
class Student {
public:
Student( char name[] ) {
}
}
int main() {
Student stud( "Kacy" ); //does not compile
char name[20] = "Kacy"; //compiles just fine
}
The char[] signature in the parameter is exactly the same as char*. In C++, it is illegal to convert a string constant char const* (the string "Kacy") to a char* because strings are immutable.
Your second example compiles because the name is an actual array. There is no change to char*.
As a solution, change your parameter to take a const string array:
Student(char const name[]);
which again is the same as
String(char const *name);
though you're better off using std::string:
#include <string>
class String
{
public:
String(std::string name);
};
C++ string literals have type "array of n const char", which decays into const char * in your use case. The implicit conversion to char * (that is, discarding the const) you're trying is deprecated, so there's a warning. Change the type in the constructor's signature or make an explicit const-cast.
From the C++ standard:
An ordinary string literal has type "array of n const char" and static storage duration
The string
"Kacy"
is not an array of characters when the compiler produces the code. Instead, it will stash the string "Kacy" somewhere in memory, and produce a pointer to that place. So what you get is a const char * pointing at the string "Kacy\0".
If you change your constructor to:
Student(const char *nmae)
you can use it both as:
Student stud("Kacy");
and as this:
char name[20] = "Kacy";
Student stud2(name);
Note here that the compiler will generate code to FILL the array name with the characters in "Kacy", which is different from just usinv "Kacy" as an argument to the Student constructor.
I have a bit of a problem with my constructor.
In my header file I declare:
char short_name_[2];
and other variables
In my constructor:
Territory(std::string name, char short_name[2], Player* owner, char units);
void setShortName(char* short_name);
inline const char (&getShortName() const)[2] { return short_name_; }
In my cpp file:
Territory::Territory(std::string name, char short_name[2], Player* owner,
char units) : name_(name), short_name_(short_name),
owner_(owner), units_(units)
{ }
My error:
Territory.cpp: In constructor ‘Territory::Territory(std::string,
char*, Player*, char)’: Territory.cpp:15:33: error: incompatible types
in assignment of ‘char*’ to ‘char [2]’
I already figured out that char[2] <=> char* but I'm not sure how to handle this about my constructor and get/setters.
Raw arrays in C++ are kind of annoying and fraught with peril. This is why unless you have a very good reason to you should use std::vector or std::array.
First off, as others have said, char[2] is not the same as char*, or at least not usually. char[2] is a size 2 array of char and char* is a pointer to a char. They often get confused because arrays will decay to a pointer to the first element whenever they need to. So this works:
char foo[2];
char* bar = foo;
But the reverse does not:
const char* bar = "hello";
const char foo[6] = bar; // ERROR
Adding to the confusion, when declaring function parameters, char[] is equivalent to char*. So in your constructor the parameter char short_name[2] is really char* short_name.
Another quirk of arrays is that they cannot be copied like other types (this is one explanation for why arrays in function parameters are treated as pointers). So for example I can not do something like this:
char foo[2] = {'a', 'b'};
char bar[2] = foo;
Instead I have to iterate over the elements of foo and copy them into bar, or use some function which does that for me such as std::copy:
char foo[2] = {'a', 'b'};
char bar[2];
// std::begin and std::end are only available in C++11
std::copy(std::begin(foo), std::end(foo), std::begin(bar));
So in your constructor you have to manually copy the elements of short_name into short_name_:
Territory::Territory(std::string name, char* short_name, Player* owner,
char units) : name_(name), owner_(owner), units_(units)
{
// Note that std::begin and std::end can *not* be used on pointers.
std::copy(short_name, short_name + 2, std::begin(short_name));
}
As you can see this is all very annoying, so unless you have a very good reason you just should use std::vector instead of raw arrays (or in this case probably std::string).
When a function wants an array as argument, it gets a pointer to the first element of an array instead. This pointer cannot be used to initialize an array, because it's a pointer, not an array.
You can write functions that accept references to arrays as arguments:
void i_dont_accept_pointers(const char (array&)[2]) {}
The problem here is, that this array reference cannot be used to initialize another array.
class Foo {
char vars[2];
Foo(const char (args&)[2])
: vars(args) // This will not work
{}
};
C++ 11 introduced std::array to eliminiate this and other problems of arrays. In older versions, you will have to iterate through the array elements and copy them individually or use std::copy.
C++ as C holds most of the rules of C.
In case of C, always use char* to pass array because that how C looks at it. Even sizeof (short_name_) will be 8 or 4 when passed to function.
Now, you have a space of 2 bytes in variable short_name_
Constructor allocated memory for two bytes in short_name_ and you need to copy the bytes into that or use a char * pointer and assume it's size if 2.
Chapter 9 from Expert C Programming: Deep C Secrets is good read to understand it.
For simplicity this could be C style code.
#include <stdio.h>
#include <iostream>
using namespace std;
class Territory {
private:
string s;
char c[2];
public:
Territory(std::string a, char b[2] /*visualize as char *b*/) {
s = a;
c[0] = b[0]; //or use strcpy
c[1] = b[1];
}
void PrintMe() {
printf ("As string %s as char %c or %s\n",this->s.c_str(), c[0],c);
}
};
main () {
Territory a("hello", "h");
a.PrintMe();
}
I have following Structure in my Program.
#define WIFI_DEVICE_NAME 100
#define WIFI_SERIAL_NO 13
#define WIFI_PROD_NAME 7
typedef struct WiFiDeviceInfo
{
char name[WIFI_DEVICE_NAME];
char fullname [WIFI_DEVICE_NAME];
char productname[WIFI_PROD_NAME];
char serialnumber[WIFI_SERIAL_NO];
};
This Struct is used in the various places. Some time some of the fields may remain empty. So while copying using strcpy_s(), it fails. So I tried with strlen() before doing any copy operation.
I modified the struct and came up with the following design.
typedef struct WiFiDeviceInfo
{
char name[WIFI_DEVICE_NAME];
unsigned short nLenName;
char fullname [WIFI_DEVICE_NAME];
unsigned short nLenFullName;
char productname[WIFI_PROD_NAME];
unsigned short nproductname;
char serialnumber[WIFI_SERIAL_NO];
};
I can't use STL here since its legacy code, which doesn't use STL.
Is there any better way to design the structure.
This modification is good. Since you are now storing the actual length of string using the member variables, I would suggest that you use pointers to char and allocate required memory at runtime.
This would be useful from memory perspective. I mean you should do this...
typedef struct WiFiDeviceInfo
{
char* name;
unsigned short nLenName;
char* fullname;
unsigned short nLenFullName;
char* productname;
unsigned short nproductname;
char* serialnumber; // Convert the serialnumber to a pointer as well
unsigned short nserialnumber;
};
Add constructor and destructor to the struct to handle memory, like setting to NULL, delete pointers etc.