Assigning a string of characters to a char array - c++

I Want to know why the first statements works and why not second one in c++
char a[10]="iqbal"; // it works
a="iqbal"; // does not work

Strictly speaking, an array is not a pointer! And an array ( base address of the array ) cant be a modifiable lvalue. ie it cannot appear on the left hand side of an assignment operator.Arrays decay into pointers only in certain circumstances. Read this SO post to learn when arrays decay into pointers. Here is one more nice article which explains the differences between arrays and pointers
Also read about lvalues and rvalues here so that you get an idea of things which cannot appear on the LHS of =
char a[10]="iqbal";  // it works
In this case, internally what happens is
a[0] = 'i';
a[1] = 'q';
.
.
a[5] = '\0';
So everything is fine as array[i] is a modifiable lvalue.
a="iqbal"; // does not work
Internally, this is roughly equivalent to
0x60000(Address of a, but is a simple number here ) = Address of "iqbal"
This is wrong as we cannot assign something to a number.

The char array a will be static and can not be changed if you initialize it like this. Anyway you can never assign a character string a="iqbal" in c. You have to use strncpy or memcpy for that. Otherwise you will try to overwrite the pointer to the string, and that is not what you want.
So the correct code would do something like:
char a[10];
strncpy(a, "iqbal", sizeof(a) - 1);
a[sizeof(a) - 1] = 0;
The -1 is to reserve a byte for the terminating zero. Note, you will have to check for yourself if the string is null terminated or not. Bad api. There is a strlcpy() call that does this for you but it is not included in glibc.

The first line is not a statement but a declaration with an initialization.
The second line is an expression statement with the assignment operator.
You cannot assign arrays in C.
But you can initialize an array with the elements of a string literal.

why the first statements works and why not second one in c++
Because they are different statements, almost wholly unrelated. Do not be confused by the fact that they both use the = symbol. In one case, it represents object initialization. In the other case, the assignment operator.
Your first line is legal because it is legal to initialize aggregates, including character arrays.
Your second line is not legal because it is not legal to assign to an array.
Since this is C++, may I suggest that you avoid naked arrays? For character strings use std::string. For other arrays use std::vector. If you do, you example becomes:
std::string a = "iqbal"; // it works
a="iqbal"; // so does this

When writing
char a[10]="iqbal"
You are initializing the elements of the character array a with the characters. We can do the same with int type (note that the char type gets a slightly different treatment) :
int a[10]={1,2,...};
But writing the following after declaration part would be invalid as a would be treated just like a pointer. So writing something like
a={1,2,...};
or a="iqbal"
won't be making any sense!

try:
char a[10]="iqbal";
char *my_a = a;
and work with my_a.

In C++11 you can use a lambda to do the initialization, like so:
bool test = true;
/*const*/ char a[10] = { //Aggregate initialization
[=] //capture by value
()//no parameters
{ //start lambda
switch (test) {
case true: return *"test=true"; //*"xxx" don't return a pointer, but the 'string' itself
case false: return *"test=false";
} //switch
}()}; //}, close the lambda, (), call it, }; close aggregate initialization
This comes in handy when your environment does not support std::string, like NVidia's CUDA or some strange embedded environment.
The lambda gets to be inlined, so internally it translates to char a[10] = test?"xxx":"yyy";
If you have the option to do so, you obviously want to always use std::string, because fixed sized char buffers are fundamentally a bad idea.
If you use std::string you can convert that to a char array using: chararray = mystring.c_str();. Which is useful if you insist on using printf: printf("s = %s", mystring.c_str());.

You cannot assign a string literal to a char array after the latter's declaration.
A nice, simple & effective alternative is to use std::strcpy to do so, like so:
struct S
{
char name[30];
};
S s;
std::strcpy( s.name,
"The moribunds salute you." );

Related

A value of type "*const char *" cannot be assigned to an entity of type "char *"

So I am trying to avoid using strings for this. I am basically trying to make a string array.
char **hourtimes = (char**)malloc(100 * sizeof(char*));
for (int i = 0; i < 100; i++) {
(*hourtimes) = (char*)malloc((100 * sizeof(char)));
}
So I made a string array basically here
Now, I want to make hourtimes[0] = "twelve";
I tried doing *hourtimes = "twelve";
but I get the same error, I think this works in c, but I'm using c++
hourtimes[0][0] = 't';
hourtimes[0][1] = 'w';
etc works just fine but that would be too cumbersome
*hourtimes = "twelve" is setting *hourtimes to point to an immutable string literal. You are then trying to modify that immutable string. What you want to do is copy "twelve" into *hourtimes.
strcpy(hourtimes[0],"twelve");
Note: This answer was written at a time when the question was tagged for C. C++ will have different preferred ways of doing this kind of thing.
The error message tells you exactly what's wrong: You can't assign a const char * to a char *. What does that mean, though?
Both const char * and char * are types. They are, in fact, very nearly the same type; one is a pointer to a character, and the other is a pointer to a constant character. That means that the latter can't be changed1; that's, after all, what "constant" means. So when you try to tell the compiler to treat a pointer to a constant type as a pointer to a non-const type, it'll give you an error -- because otherwise it'd have no way to guarantee that the string isn't modified.
"whatever" is always a const char *, not a char *, because that's stored in memory that's generally not meant to be modified, and the compiler can make some really neat optimizations if it can safely assume that it's unchanged (which, because it's const, it can).
I won't tell you how to "properly" write the code you're going for, because if you're using C++, you should be using std::vector and std::string instead of anything with pointers whenever possible, and that probably includes here. If, for whatever reason, you need to use pointers, the comments have covered that well enough.
1: Okay, yes, it can -- but that's outside the scope of this answer, and I don't want to confuse any beginners.
In your allocation loop, (*hourtimes) is the same as hourtimes[0], so you are assigning your allocated sub-arrays to the same slot in the main array on each loop iteration, causing memory leaks and uninitialized slots. You need to use hourtimes[i] instead:
char **hourtimes = (char**)malloc(100 * sizeof(char*));
for (int i = 0; i < 100; i++) {
hourtimes[i] = (char*)malloc(100 * sizeof(char));
}
And don't forget to deallocate the arrays when you are done with them:
for (int i = 0; i < 100; i++) {
free(hourtimes[i]);
}
free(hourtimes);
Now, a string literal has type const char[N], where N is the number of characters in the literal, + 1 for the null terminator. So "twelve" would be a const char[7].
Your arrays only allow char* pointers to be stored, but a const char[N] decays into a const char* pointer to the first char. You can't assign a const char* to a char*, thus the compiler error.
Even if it were possible to do (which it is, but only with a type-cast), you shouldn't do it, because doing so would cause a memory leak as you would lose your original pointer to the allocated array, and worse free() can't deallocate a string literal anyway.
What you really want to do is copy the content of the string literal into the allocated array storage. You can use strncpy() for that:
strncpy(hourtimes[0], "twelve", 100);
Now, with all of that said, this is the C way of handling arrays of strings. The C++ way is to use std::vector and std::string instead:
#include <string>
#include <vector>
std::vector<std::string> hourtimes(100);
...
hourtimes[0] = "twelve";
This is a string literal, which can be used as a pointer to a constant char, but not as a pointer to a non-const char.
"twelve"
You do however attempt to assign it to a pointer to non-const char.
hourtimes[0] = "twelve";
That is what the compiler does not like.

Initialization of Chars [duplicate]

This question already has answers here:
How to initialize all members of an array to the same value?
(26 answers)
Closed 8 years ago.
I have been wondering, why can I not write my code like so:
char myChar[50];
myChar = "This is a really cool char!";
Or at least like this:
char myChar[50];
myChar[0] = "This is a really cool char!";
The second way makes more sense that it should work, to me, seeing that I would
start the array at the point I want it to start moving the letters into each spot in the
array.
Does anyone know why C++ does not do this? And can you show me the reasoning behind the
right way to do it?
Thank you all in advance!
The first line:
char myChar[50];
...allocates an array of 50 characters on the stack. The second line:
myChar = "This is a really cool char!";
Is attempting to assign a const static string (which exists in read-only memory in the text segment of your code) to the address of the beginning of the array. This is an incompatible LVALUE/RVALUE matcing/assignment. This approach:
const char* myChar = "This is a really cool char";
Will work, as the assignment of a pointer to address a string literal must be done at initialization time. There are potential exceptions, as in assigning a const char* pointer to a string literal like so:
/*******************************************************************************
* Preprocessor Directives
******************************************************************************/
#include <stdio.h>
/*******************************************************************************
* Function Prototypes
******************************************************************************/
const char* returnErrorString(int iError);
/*******************************************************************************
* Function Definitions
******************************************************************************/
int main(void) {
int i;
for (i=(-1); i<3; i++) {
printf("i=%d - Error String:%s\n", returnErrorString(i));
}
return 0;
}
const char* returnErrorString(int iError) {
const char* ret = NULL;
switch (iError) {
case 0:
ret = "No error";
break;
case (-1):
ret = "Invalid input";
break;
default:
ret = "Unknown error";
break;
}
return ret;
}
You might benefit from reading the post in my references below. It will give you some info on how code, variables, constants, etc, are broken into different segments of the final binary, and why some approaches don't even make sense. Also, it would be beneficial to read up a bit on terminology like integer literals, string literals, l-values, r-values, etc.
Good luck!
References
Difference between declared string and allocated string, Accessed 2014-05-01, <https://stackoverflow.com/questions/16021454/difference-between-declared-string-and-allocated-string>
You must initialise the array of chars inside the declaration of the array. There is actually no reason for not doing so, as if not, your array will contain garbage values until you initialise it. I advise you to look at this link:
Char array declaration and initialization in C
Also, you are allocating a char array of size 50 but only using 28 elements of it, this would appear to me to be a waste...
Try the following for simple string initialisations:
char mychar[11] = "hello world";
Or...
char *mychar = "hello world";
I hope this helps...
If you want to think of this in holistic terms, the reason is because myChar isn't a string -- it's just an array of char. Hence "FooGHBar" and char [50] are completely different types. Related in a sense, but really not.
Now some might say, "but "FooBar" is a string, and char [50] is really just a string too." But that is going on the assumption that myChar is the same as "FooBar", and it's not. It's also assuming that the compiler understands that both char[50] and char* are pointers to strings. The compiler doesn't understand that. There could be any manner of thing stored in those places that have nothing to do with strings.
"But myChar is just a pointer?"
That is the reason why people think that the assignment should be a natural thing -- but the fundamental premise is wrong. myChar is not a pointer. It is an array. A name which refers to an array will decay into a pointer at the drop of a hat, but an array is not a pointer.

Assigning value to char array [duplicate]

This question already has answers here:
Assigning char array a value in C
(2 answers)
Closed 8 years ago.
I get no error when I type
char a[10] = "Hi";
But when I change it to the following, I get an error: Array type char is not assignable.
char a[10];
a = "Hi";
Why is array type char not assignable? Is it because the language is written that way on purpose or am I missing a point?
An array is not a modifiable lvalue
use
char a[10];
strcpy(a, "Hi");
The C++ way of doing this, as I commented above, would be to use std::string instead of char[]. That will give you the assignment behavior you're expecting.
That said, the reason you're only getting an error for the second case is that the = in these two lines mean different things:
char a[10] = "Hi";
a = "Hi";
The first is an initialization, the second is an assignment.
The first line allocates enough space on the stack to hold 10 characters, and initializes the first three of those characters to be 'H', 'i', and '\0'. From this point on, all a does is refer to the position of the the array on the stack. Because the array is just a place on the stack, a is never allowed to change. If you want a different location on the stack to hold a different value, you need a different variable.
The second (invalid) line, on the other hand, tries to change a to refer to a (technically different) incantation of "Hi". That's not allowed for the reasons stated above. Once you have an initialized array, the only thing you can do with it is read values from it and write values to it. You can't change its location or size. That's what an assignment would try to do in this case.
The language does not allow assigning string literals to character arrays. You should use strcpy() instead:
strcpy(a, "Hi");
a is a pointer to the array, not the array itself. It cannot be reassigned.
You tagged with C++ BTW. For that case better use std::string. It's probably more what you're expecting.
Simple, the
char a[10] = "Hi";
is a little "extra feature", as it cannot be done like that on run-time.
But that's the reason for C/C++ standard libraries.
#include <string.h>
// ...
strcpy(a,"Test"); // STR-ing C-o-PY.
This comes from the C's standard library. If using C++ you should use std::string, unless you really want to suck all the possible performance from your destination PC.
this is because initialization is not an assignment. the first thing which works is an initialization, and the second one, which does not work, as expected, is assignment. you simply cant assign values to arrays you should use sth like strcpy or memcpy. or you can alternatively use std::copy from <algorithm>
It is so simple,(=) have two different mean assignment and initialization. You can also write your code like that
#include <iostream>
using namespace std;
int main ()
{
char message[3] = {'H', 'i', '\0'};
cout << message<< endl;
return 0;
}
in this code you have no need to write a difficult code or function and even no need of string.h

Quick new operator issue

I know this is really easy and I'm looking over something but this is what I have...:
typedef struct
{
char s1[81];
char s2[81];
char s3[81];
}Rec;
int main()
{
Rec *a[10];
a[0] = (Rec*)new unsigned char(sizeof(Rec));
a[0]->s1= "hello";
printf("a[0] = %s\n",a[0]->s1);
delete(a[0]);
getchar();
return 0;
}
Now, the line
a[0]->s1= "hello";
is complaining about the expression must be a modifiable lvalue. I am pretty sure it's how I'm casting it in my new operator line and has it needs to be a long value or something but I'm not sure of the code to do this... easy i know but yeah. Any help would be much appreciated
You cannot assign to char arrays like that. Either use strcpy, or change your char arrays to std::string.
strcpy(a[0]->s1, "hello");
Why are you doing this:
a[0] = (Rec*)new unsigned char(sizeof(Rec));
instead of this:
a[0] = new Rec;
Two things. The line
a[0] = (Rec*)new unsigned char(sizeof(Rec));
allocates a single unsigned char that gets initialized to the value sizeof(Rec). You probably meant
a[0] = (Rec*)new unsigned char[sizeof(Rec)];
or better yet
a[0] = new Rec;
Second, you cannot assign a string literal to an array of chars, you need to copy the characters one by one, e.g.
char s[80];
s = "hello"; // won't work
strcpy(s, "hello"); // correct
You should however use std::string in this case.
I guess that you've done a lot of C in your life. Keep in mind that C++ is different language, which happen to share with C most of its syntax and some of its standard library. That means something that is perfectly fine in C might be quite ugly (or even dangerous) in C++.
With that said, let's rewrite your code in a more "C++-ish" way:
#include <iostream> // std::cout, std::endl
#include <string> // std::string
struct Rec // typedef is implicit for structs in C++
{
std::string s1; // use std::string instead of char arrays
std::string s2;
std::string s3;
}; // don't forget the semicolon!
int main()
{
Rec * a[10];
a[0] = new Rec; // allocates the right amount of memory, no need to cast
a[0]->s1 = "hello"; // std::sring handles the assignment for you
std::cout << "a[0] = " << a[0]->s1 << std::endl; // use iostreams
delete a[0]; // delete is an operator, not a function, no need for parentheses
getchar(); // warning, this is not portable
return 0;
}
As you see, new is not an "improved malloc". It's typesafe (no cast needed), it's safer to use (it allocates the exact amount of memory required, no need for sizeof), and it also does something that malloc cannot do: it invokes the class' constructor (just as delete invokes a destructor).
In C++, as in C, allocation is distinct from initialization. While in C you could just memset the block to zero, in C++ object construction can be a bit more complex. As such, you should never use malloc to create objects of classes that have non-trivial constructors (or have fields that don't have non trivial constructors - Rec is such a case). Because new always works, and has additional features, you should use it anyway.
The problem is not with your casting. Your new expression allocates a single unsigned char and initializes it to the sizeof(Rec) instead of allocating enough space as new unsigned char[sizeof(Rec)]; would do. That said, the types of s1 and "hello" are different and you can't assign one with the other. You should be using something like strcpy, but since you tagged this C++ then you would be better off using std::string. Also, why don't you just call new Rec;?
a[0] is a pointer to an array of chars that can't be modified -- a[0] will always point to the same address.
you need to use strcpy to copy from your "hello" string to a[0]

C++ strings: [] vs. *

Been thinking, what's the difference between declaring a variable with [] or * ? The way I see it:
char *str = new char[100];
char str2[] = "Hi world!";
.. should be the main difference, though Im unsure if you can do something like
char *str = "Hi all";
.. since the pointer should the reference to a static member, which I don't know if it can?
Anyways, what's really bugging me is knowing the difference between:
void upperCaseString(char *_str) {};
void upperCaseString(char _str[]) {};
So, would be much appreciated if anyone could tell me the difference? I have a hunch that both might be compiled down the same, except in some special cases?
Ty
Let's look into it (for the following, note char const and const char are the same in C++):
String literals and char *
"hello" is an array of 6 const characters: char const[6]. As every array, it can convert implicitly to a pointer to its first element: char const * s = "hello"; For compatibility with C code, C++ allows one other conversion, which would be otherwise ill-formed: char * s = "hello"; it removes the const!. This is an exception, to allow that C-ish code to compile, but it is deprecated to make a char * point to a string literal. So what do we have for char * s = "foo"; ?
"foo" -> array-to-pointer -> char const* -> qualification-conversion -> char *. A string literal is read-only, and won't be allocated on the stack. You can freely make a pointer point to them, and return that one from a function, without crashing :).
Initialization of an array using a String literal
Now, what is char s[] = "hello"; ? It's a whole other thing. That will create an array of characters, and fill it with the String "hello". The literal isn't pointed to. Instead it is copied to the character-array. And the array is created on the stack. You cannot validly return a pointer to it from a function.
Array Parameter types.
How can you make your function accept an array as parameter? You just declare your parameter to be an array:
void accept_array(char foo[]);
but you omit the size. Actually, any size would do it, as it is just ignored: The Standard says that parameters declared in that way will be transformed to be the same as
void accept_array(char * foo);
Excursion: Multi Dimensional Arrays
Substitute char by any type, including arrays itself:
void accept_array(char foo[][10]);
accepts a two-dimensional array, whose last dimension has size 10. The first element of a multi-dimensional array is its first sub-array of the next dimension! Now, let's transform it. It will be a pointer to its first element again. So, actually it will accept a pointer to an array of 10 chars: (remove the [] in head, and then just make a pointer to the type you see in your head then):
void accept_array(char (*foo)[10]);
As arrays implicitly convert to a pointer to their first element, you can just pass an two-dimensional array in it (whose last dimension size is 10), and it will work. Indeed, that's the case for any n-dimensional array, including the special-case of n = 1;
Conclusion
void upperCaseString(char *_str) {};
and
void upperCaseString(char _str[]) {};
are the same, as the first is just a pointer to char. But note if you want to pass a String-literal to that (say it doesn't change its argument), then you should change the parameter to char const* _str so you don't do deprecated things.
The three different declarations let the pointer point to different memory segments:
char* str = new char[100];
lets str point to the heap.
char str2[] = "Hi world!";
puts the string on the stack.
char* str3 = "Hi world!";
points to the data segment.
The two declarations
void upperCaseString(char *_str) {};
void upperCaseString(char _str[]) {};
are equal, the compiler complains about the function already having a body when you try to declare them in the same scope.
Okay, I had left two negative comments. That's not really useful; I've removed them.
The following code initializes a char pointer, pointing to the start of a dynamically allocated memory portion (in the heap.)
char *str = new char[100];
This block can be freed using delete [].
The following code creates a char array in the stack, initialized to the value specified by a string literal.
char [] str2 = "Hi world!";
This array can be modified without problems, which is nice. So
str2[0] = 'N';
cout << str2;
should print Ni world! to the standard output, making certain knights feel very uncomfortable.
The following code creates a char pointer in the stack, pointing to a string literal... The pointer can be reassigned without problems, but the pointed block cannot be modified (this is undefined behavior; it segfaults under Linux, for example.)
char *str = "Hi all";
str[0] = 'N'; // ERROR!
The following two declarations
void upperCaseString(char *_str) {};
void upperCaseString(char [] _str) {};
look the same to me, and in your case (you want to uppercase a string in place) it really doesn't matters.
However, all this begs the question: why are you using char * to express strings in C++?
As a supplement to the answers already given, you should read through the C FAQ regarding arrays vs. pointers. Yes it's a C FAQ and not a C++ FAQ, but there's little substantial difference between the two languages in this area.
Also, as a side note, avoid naming your variables with a leading underscore. That's reserved for symbols defined by the compiler and standard library.
Please also take a look at the http://c-faq.com/aryptr/aryptr2.html The C-FAQ might prove to be an interesting read in itself.
The first option dynamically allocates 100 bytes.
The second option statically allocates 10 bytes (9 for the string + nul character).
Your third example shouldn't work - you're trying to statically-fill a dynamic item.
As to the upperCaseString() question, once the C-string has been allocated and defined, you can iterate through it either by array indexing or by pointer notation, because an array is really just a convenient way to wrap pointer arithmetic in C.
(That's the simple answer - I expect someone else will have the authoritative, complicated answer out of the spec :))