I'm newbie in C world and I have two probably stupid questions.
I'm reading about structures in C and here is where I stuck. Let say we have structure like this
typedef structs {
char model[50];
int yearOfManufacture;
int price;
} Car;
Car Ford;
Ford.yearOfManufacture = 1997;
Ford.price = 3000;
//The line below gives me an error "Array type char[50] is not assignable
Ford.model = "Focus"
How to pass text into Ford.model in that case ?
My second question is also about strings.
This code works fine
char model[50] = "Focus";
printf("Model is %s", model);
But this one doesn't
char model[50];
model = "Focus";
Can anyone explain why it doesn't work ?
That's not how you copy strings in C. Try
strcpy(Ford.model, "Focus");
Alternatively (but with very different semantics):
typedef structs {
char const *model;
int yearOfManufacture;
int price;
} Car;
model = "Focus";
These C FAQs explain more about the issue:
Assign to array
How can an array be an lvalue, if you can't assign to it?
There are two ways to "put values in objects":
with initialization, when the object is created
with assignment, after the object is created
Though the syntax is similar, they represent different concepts.
You can initialize an array, but you cannot assign to it.
Also there's a special construct to initialize char arrays based on string literals
char arr[] = "foobar";
char arr[] = {'f', 'o', 'o', 'b', 'a', 'r', '\0'};
int arr[] = {1, 2, 3, 4};
// ...
but, assignement must be done element by element
char arr[4];
arr[0] = arr[1] = arr[2] = 'X';
arr[3] = '\0';
int arr[4];
arr[0] = arr[1] = arr[2] = 42;
arr[3] = -1;
A "special" way to assign elements of a char arrays one-by-one with a single statement is to use the library function strcpy() with prototype in <string.h>
#include <string.h>
int main(void) {
char arr[10];
strcpy(arr, "foo"); // same as arr[0]='f'; arr[1]=arr[2]='o'; arr[3]='\0';
return 0;
}
This (Ford.model = "Focus") is not possible. You have to copy the string into the array in the struct, best with strcpy:
strcpy(Ford.model, "Focus");
If your stdlib supports it, you should also consider an overflow safe version, e.g strncpy:
strncpy(Ford.model, "Focus", sizeof Ford.model);
At least I think its an extension function and not in the standard... I'm not sure.
You can't assign to a character array with =, you can only initialize it.
When you write
char model[50] = "Focus";
that is a initialization.
When you write
model = ...
that is an assignment. And, as I said, assignment to character arrays is not allowed.
You need to copy to the character array using strcpy(), e.g. strcpy(model, "Focus").
You can assign a string during definition, but anywhere else you have to use a different method, like the strcpy() function:
char model[50];
strcpy(model, "Focus");
Related
I've tried this: char **foo, which is is a string array,
but warnings generate, when I try to assign values to it:
char **baz = {"Hello,", "world!"}
So, ...
how to create a dynamic string (char *) array in C, without specifying the size?
how do to assign values to a char ** array?
NOTE:
char *not_this[50] isn't the answer
this is my 2nd question on Stackoverflow
C is willing to automatically size, allocate, and initialize arrays for you. With one exception, however, there is no way to automatically initialize a pointer that points to some other array.
Here is automatic sizing and allocation of an array:
int a[] = {1, 2, 3};
The brackets [] are empty -- you don't have to explicitly specify the size -- because the compiler can see from the initializer that the array should have size 3.
Here is another example, using char:
char s1[] = {'H', 'e', 'l', 'l', 'o', 0};
Here is a much more convenient shortcut form:
char s2[] = "world";
Here is the exception I was talking about:
char *s3 = "hidden";
In this case, the compiler allocates a hidden, unnamed array containing the string "hidden", then initializes s3 to point to it. This is just about perfectly equivalent to the more explicit setup
char a2[] = "hidden";
char *s3a = a2;
except for the visibility of the intermediate array a2.
Putting all this together, you can initialize an array of pointers to char like this:
char *strarray[] = { "Hello", "world" };
This is equivalent (again, except for the visibility of the actual arrays holding the strings) to the more explicit
char a3[] = "Hello";
char a4[] = "world";
char *strarray2[] = { a3, a4 };
But you can not directly do anything along the lines of
char **dynstrarray = { ... };
The reason you can't do it is because dynstrarray is fundamentally a pointer, and there's no general mechanism in C to automatically allocate something for a pointer like this to point to. Again, the only time C will automatically allocate something for a pointer to point to is the special case for pointer to char, as demonstrated by s3 above.
So if you want to initialize a pointer like dynstrarray, your only choice is to do it explicitly, yourself. You could initialize it to point to an array of pointers to char that you had already constructed, like this:
char a3[] = "Hello";
char a4[] = "world";
char *strarray2[] = { a3, a4 };
char **dynstrarray[] = strarray2;
Or, more commonly, you would use malloc to dynamically allocate some memory for dynstrarray to point to. In that case (but only in that case) you would also have the option of resizing dynstrarray later, using realloc.
You can create an array of char * as follows:
char *baz[] = {"Hello,", "world!"};
have a look at this answer.
You then only need to swap every occurence of int for char*.
Natively there are no dynamically sized arrays in C (if this is what you want) but you can create them on your own as shown by the linked answer.
I am trying to do the following, create a multy-charr array with other char variables.
char data_info_1[] = "Wellcome.";
char data_info_2[] = "Please";
char data_info_3[] = "If";
int size_line= sizeof(data_info_1)/sizeof(data_info_1[0]);
char data_info[3][size_line]={{data_info_1},{data_info_2},{data_info_3}};
One solution would be the following one, but I am not interested in just putting the string right in the data_info variable
char data_info[3][size_line]={{"Wellcome"},{"Please"},{"If"}};
Could you please explain me why the first thing that I have writen is not valid. And if there is a solution to my problem.
Thanks.
To answer your question, neither of your solutions is correct, you can't initialize a 2D array of chars like that.
The second option would be valid if it wasn't a variable sized array, i.e.
char data_info[3][10]={"Wellcome", "Please" ,"If"};
^
Valid -> fixed size
Assignments like those would be possibe if you had an array of pointers:
char *data_info[] = {data_info_1, data_info_2, data_info_3}; //1
Or
const char *data_info[] = {"Wellcome", "Please", "If"}; //2
But these may not be what you need.
Option 1 will contain pointers to the original strings, any changes made to them through those pointers will be reflected in the original strings.
Option 2, the pointers are being initialized with string literals and those can't be changed, that's why I added the const qualifier as a metter of safety.
If neither of these constrains work for you, you'll need to copy the strings with something like strcpy, strncpy or better yet memcpy:
#include <string.h>
//...
memcpy(data_info[0], data_info_1, sizeof data_info_1);
memcpy(data_info[1], data_info_2, sizeof data_info_2);
memcpy(data_info[2], data_info_3, sizeof data_info_3);
Arrays may not be initialized by arrays. You may initialize a character array with string literals as you did in this declaration
char data_info[3][size_line]={{"Wellcome"},{"Please"},{"If"}};
Relative to your case you could declare an array of pointers to char like for example
char * data_info[] = { data_info_1, data_info2, data_info3 };
Some remarks:
you do not need to divide by sizeof char becuse it is by definition 1
You can only use constant expressions when defining or initializing global variables char data_info[3][sizeof(data_info_1)];
To "store" one char array in other you need to copy it. Initialization will not work as you cannot assign the arrays.
#include <string.h>
char data_info_1[] = "Wellcome.";
char data_info_2[] = "Please";
char data_info_3[] = "If";
char data_info[3][sizeof(data_info_1)];
void foo(void)
{
strcpy(data_info[0], data_info_1);
strcpy(data_info[1], data_info_2);
strcpy(data_info[2], data_info_3);
}
only structs or unions can be assigned. So you can wrap array into the struct and the assignment or initializations will copy the whole array.
struct stringWR
{
char str[50];
};
struct stringWR data_info_1 = {"Wellcome."};
struct stringWR data_info_2 = {"Please"};
struct stringWR data_info_3 = {"If"};
struct stringWR data_info[3];
void foo(void)
{
data_info[0] = data_info_1;
data_info[1] = data_info_1;
data_info[2] = data_info_1;
}
void bar(void)
{
struct stringWR data_info[3] = {data_info_1, data_info_2, data_info_2};
}
I've a function which receives a const char* and I want to convert it to lowercase. But I get the error:
error: array initializer must be an initializer list or string literal
I tried to copy the string variable to another array so that I could lower case it. But I think I've got something confused.
This is my function:
int convert(const char* string)
{
char temp[] = string;
temp = tolower(temp); //error is here
//do stuff
}
I'm struggling to understand what this error means, could someone help in explaining it?
tolower takes a single character and returns it in lowercase.
Even if it didn't, arrays aren't assignable. Arrays and pointers are not the same thing.
You presumably want to do something like:
char *temp = strdup(string); // make a copy
// adjust copy to lowercase
unsigned char *tptr = (unsigned char *)temp;
while(*tptr) {
*tptr = tolower(*tptr);
tptr++;
}
// do things
// release copy
free(temp);
Make sure you understand the difference between the heap and the stack, and the rules affecting string literals.
First of all, tolowertakes char or int, not string.
but even if you passed char, your code wouldn't work, because this error array initializer must be an initializer list or string literal ,means you have to initialize it using one of the following methods:
char arr[4] = {'h', 'e', 'y','\0'}; // initializer list
char arr[4] = "hey"; // string literal
char arr[] = "hey"; // also a string literal
char arr[4];
arr[0] = 'h';
arr[1] = 'e';
arr[2] = 'y';
arr[4] = '\0';
Please note that, tolower() takes a character and not a string:
int tolower ( int c );
Also you are trying to copy the string from string to temp[] variable. There in no overloading of the = operator in C to copy the string into char array.
Now about your error:
error: array initializer must be an initializer list or string literal
It says that the array must be initialized via an list of initial individual items or you can directly assign a string literal.
E.g:
char temp[] = "Hi";
char temp[] = {'H','i','\0'};
Also, check your statement:
temp = tolower(temp);
Here the return type of tolower() is int that you are assigning it to the array temp which is improper.
You can use the following snippet using strlwr():
int convert(const char* string)
{
char *temp= malloc(strlen(string)+1);
strcpy(temp,string);
strlwr(temp);
//do your stuff
}
Why is the following code illegal?
typedef struct{
char a[6];
} point;
int main()
{
point p;
p.a = "onetwo";
}
Does it have anything to do with the size of the literal? or is it just illegal to assign a string literal to a char array after it's declared?
It doesn't have anything to do with the size. You cannot assign a string literal to a char array after its been created - you can use it only at the time of definition.
When you do
char a[] = "something";
it creates an array of enough size (including the terminating null) and copies the string to the array. It is not a good practice to specify the array size when you initialize it with a string literal - you might not account for the null character.
When you do
char a[10];
a = "something";
you're trying to assign to the address of the array, which is illegal.
EDIT: as mentioned in other answers, you can do a strcpy/strncpy, but make sure that the array is initialized with the required length.
strcpy(p.a, "12345");//give space for the \0
You can never assign to arrays after they've been created; this is equally illegal:
int foo[4];
int bar[4];
foo = bar;
You need to use pointers, or assign to an index of the array; this is legal:
p.a[0] = 'o';
If you want to leave it an array in the struct, you can use a function like strcpy:
strncpy(p.a, "onetwo", 6);
(note that the char array needs to be big enough to hold the nul-terminator too, so you probably want to make it char a[7] and change the last argument to strncpy to 7)
Arrays are non modifiable lvalues. So you cannot assign to them. Left side of assignment operator must be an modifiable lvalue.
However you can initialize an array when it is defined.
For example :
char a[] = "Hello World" ;// this is legal
char a[]={'H','e','l','l','o',' ','W','o','r','l','d','\0'};//this is also legal
//but
char a[20];
a = "Hello World" ;// is illegal
However you can use strncpy(a, "Hello World",20);
As other answers have already pointed out, you can only initialise a character array with a string literal, you cannot assign a string literal to a character array. However, structs (even those that contain character arrays) are another kettle of fish.
I would not recommend doing this in an actual program, but this demonstrates that although arrays types cannot be assigned to, structs containing array types can be.
typedef struct
{
char value[100];
} string;
int main()
{
string a = {"hello"};
a = (string){"another string!"}; // overwrite value with a new string
puts(a.value);
string b = {"a NEW string"};
b = a; // override with the value of another "string" struct
puts(b.value); // prints "another string!" again
}
So, in your original example, the following code should compile fine:
typedef struct{
char a[6];
} point;
int main()
{
point p;
// note that only 5 characters + 1 for '\0' will fit in a char[6] array.
p = (point){"onetw"};
}
Note that in order to store the string "onetwo" in your array, it has to be of length [7] and not as written in the question. The extra character is for storing the '\0' terminator.
No strcpy or C99 compund literal is needed. The example in pure ANSI C:
typedef struct{
char a[6];
} point;
int main()
{
point p;
*(point*)p.a = *(point*)"onetwo";
fwrite(p.a,6,1,stdout);fflush(stdout);
return 0;
}
I am a little surprised by the following.
Example 1:
char s[100] = "abcd"; // declare and initialize - WORKS
Example 2:
char s[100]; // declare
s = "hello"; // initalize - DOESN'T WORK ('lvalue required' error)
I'm wondering why the second approach doesn't work. It seems natural that it should (it works with other data types)? Could someone explain me the logic behind this?
When initializing an array, C allows you to fill it with values. So
char s[100] = "abcd";
is basically the same as
int s[3] = { 1, 2, 3 };
but it doesn't allow you to do the assignment since s is an array and not a free pointer. The meaning of
s = "abcd"
is to assign the pointer value of abcd to s but you can't change s since then nothing will be pointing to the array.
This can and does work if s is a char* - a pointer that can point to anything.
If you want to copy the string simple use strcpy.
There is no such thing as a "string" in C. In C, strings are one-dimensional array of char, terminated by a null character \0. Since you can't assign arrays in C, you can't assign strings either. The literal "hello" is syntactic sugar for const char x[] = {'h','e','l','l','o','\0'};
The correct way would be:
char s[100];
strncpy(s, "hello", 100);
or better yet:
#define STRMAX 100
char s[STRMAX];
size_t len;
len = strncpy(s, "hello", STRMAX);
Initialization and assignment are two distinct operations that happen to use the same operator ("=") here.
1 char s[100];
2 s = "hello";
In the example you provided, s is actually initialized at line 1, not line 2. Even though you didn't assign it a value explicitly at this point, the compiler did.
At line 2, you're performing an assignment operation, and you cannot assign one array of characters to another array of characters like this. You'll have to use strcpy() or some kind of loop to assign each element of the array.
To expand on Sparr's answer
Initialization and assignment are two distinct operations that happen to use the same operator ("=") here.
Think of it like this:
Imagine that there are 2 functions, called InitializeObject, and AssignObject. When the compiler sees thing = value, it looks at the context and calls one InitializeObject if you're making a new thing. If you're not, it instead calls AssignObject.
Normally this is fine as InitializeObject and AssignObject usually behave the same way. Except when dealing with char arrays (and a few other edge cases) in which case they behave differently. Why do this? Well that's a whole other post involving the stack vs the heap and so on and so forth.
PS: As an aside, thinking of it in this way will also help you understand copy constructors and other such things if you ever venture into C++
Note that you can still do:
s[0] = 'h';
s[1] = 'e';
s[2] = 'l';
s[3] = 'l';
s[4] = 'o';
s[5] = '\0';
I know that this has already been answered, but I wanted to share an answer that I gave to someone who asked a very similar question on a C/C++ Facebook group.
Arrays don't have assignment operator functions*. This means that you cannot simply assign a char array to a string literal. Why? Because the array itself doesn't have any assignment operator. (*It's a const pointer which can't be changed.)
arrays are simply an area of contiguous allocated memory and the name
of the array is actually a pointer to the first element of the array.
(Quote from https://www.quora.com/Can-we-copy-an-array-using-an-assignment-operator)
To copy a string literal (such as "Hello world" or "abcd") to your char array, you must manually copy all char elements of the string literal onto the array.
char s[100]; This will initialize an empty array of length 100.
Now to copy your string literal onto this array, use strcpy
strcpy(s, "abcd"); This will copy the contents from the string literal "abcd" and copy it to the s[100] array.
Here's a great example of what it's doing:
int i = 0; //start at 0
do {
s[i] = ("Hello World")[i]; //assign s[i] to the string literal index i
} while(s[i++]); //continue the loop until the last char is null
You should obviously use strcpy instead of this custom string literal copier, but it's a good example that explains how strcpy fundamentally works.
Hope this helps!
I am annoyed by this... It really would be logical if:
char string[10] = "hello";
should give the same result as:
char string[10] = {0};
string = "hello"; // doesn't work!
But I guess it just doesn't work like that. Anyways, here was my workaround:
char string[10] = {0};
sprintf(string,"hello");
its almost as good, because it is short.
Strangely enough, another thing which has worked for me (though a little off-topic perhaps) is when you declare arrays of structs, you can initialize them with the good-ole double quotes like this:
struct myStruct {
char name[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
name[1] = (struct myStruct ) { "Hello" };
Incidentally, this method of initialization is known as a "compound literal"
Id love to see if anyone could explain why this works to use double quotes and not the string = "hello"; way...
This method is great if you have a lot of strings by the way, because it allows you to write code like:
#define DATA_ARRAY_SIZE 4
enum names{ BOB, GEORGE, FRANK, SARAH};
struct myStruct {
char name[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
name[BOB ] = (struct myStruct ) { "Bob" };
name[GEORGE] = (struct myStruct ) { "George" };
name[FRANK ] = (struct myStruct ) { "Frank" };
name[SARAH ] = (struct myStruct ) { "Sarah" };
Or if you're going to go all multilingual for some app:
#define NUM_LANGUAGES 4
enum languages{ ENGLISH , FRENCH , SWEDISH , ITALIAN };
struct myStruct {
char intro[NAX_NAME_LEN];
};
struct myStruct name[DATA_ARRAY_SIZE];
intro[ENGLISH ] = (struct myStruct ) { "Hello" };
intro[FRENCH ] = (struct myStruct ) { "Bonjour" };
intro[SWEDISH ] = (struct myStruct ) { "Hej" };
intro[ITALIAN ] = (struct myStruct ) { "Ciao" };
You can use this:
yylval.sval=strdup("VHDL + Volcal trance...");
Where
yylval is char*. strdup from does the job.
What I would use is
char *s = "abcd";