C - Error with mallocing a string - c

I keep getting the following errors when i try to compile my code below. I searched online for what the errors meant but nothing seemed to fit my code. Please could someone tell me where im going wrong in malllocing a string below. I want to make 5 units in that array, and this is the first one.
Errors:
assignment4.c: In function ‘readFile’:
assignment4.c:42:19: warning: assignment makes integer from pointer without a cast [enabled by default]
assignment4.c:44:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
Code:
void readFile()
{
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
listofdetails[1] = "cars";
printf("%s \n", listofdetails[1]);
free(listofdetails);
}

Use strcpy (don't forget to #include <string.h>):
strcpy(listofdetails, "cars");
Also, "%s", expects a string, not a char, if you want to print a string
printf("%s \n", listofdetails);
is what you want.
If you want to print the first character in the string:
printf("%c \n", listofdetails[0]);
But if you want a list of details (as the name suggests), you need to reserve space for the list of n string (char **), and for each string (char *):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char *strdup(const char *);
int main(void)
{
char **listofdetails = malloc(sizeof(*listofdetails) * 40);
if (listofdetails == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
listofdetails[0] = strdup("cars");
if (listofdetails[0] == NULL) {
perror("strdup");
exit(EXIT_FAILURE);
}
printf("%s\n", listofdetails[0]);
free(listofdetails[0]);
free(listofdetails);
return 0;
}
Note that strdup is not part of the standard (but is available on many implementations).
Finally, if those strings are known at compile time you don't need to use malloc at all:
const char *listofdetails[] = {
"cars",
"trucks",
"motorcycles",
/* etc */
};

The two lines
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
can be written as
char * listofdetails = malloc(40);
(sizeof(char) is defined to be 1). Still you should not use magic numbers as 40 directly in the code but use aptly named constant
#define STRING_LENGTH 40
The line
listofdetails[1] = "cars";
is wrong, since the left side is the second character location in the list of details, and you try to assign a string character to it. Use
strcpy(listofdetails, "cars");
and the same problem in the line
printf("%s \n", listofdetails[1]);
Use
printf("%s \n", listofdetails);
instead.

listofdetails[1] is char(or int) type. %s expects a char * type. The fix:
printf("%s \n", listofdetails);
If you want to print out listofdetails[1], then use %c:
printf("%c \n", listofdetails[1]);
listofdetails[1] = "cars"; tries to assign a char array to a char(or int).
Instead, you can do:
listofdetails = malloc(sizeof(char)*40);
strcpy(listofdetails, "cars");

It would appear that you want a list of strings, but you're declaration of listofdetails is only a single string.
Instead, you need to add another pointer, like so:
char **listofdetails = malloc(sizeof(char *) * 40);
Now you can use listofdetails as you intend. Please note, however, that in C, array indexes start at 0, not 1. So you probably want to use listofdetails[0] = "cars"; to set the first element of your array.

You are assigning a string to a single byte location.
listofdetails[1] = "cars"; // Problem
where listofdetails[1] indicates a single character in a character array.
You should not assign string like above. use strcpy-
strcpy(listofdetails,"cars");
Else you can assign like this also
char *listofdetails = "cars";
It does not require memory allocation.
Try the below changes-
void readFile()
{
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
strcpy(listofdetails,"cars");
printf("%s \n", listofdetails);
free(listofdetails);
}
Use string.h and stdlib.h header file also.

a char is a single character (e.g. 'a')
char* is a pointer. in your case you allocate 40 (single) characters (malloc) and assign the address of the first to listofdetails. use strcpy, as Alter Mann wrote, to copy a string literal or any null-terminated sequence of chars to your listofdetails. to complete Alter Mann's example:
char * listofdetails;
listofdetails = malloc(sizeof(char)*40);
strcpy(listofdetails, "cars"); // make sure that the string on the right does not exceed 40 characters!
printf("%s\n", listofdetails); // will print "cars" on a single line
free(listofdetails);
example for array of strings:
char ** listofdetails;
listofdetails = malloc(sizeof(char*) * ARRAYSIZE);
listofdetails[0] = malloc(sizeof(char) * STRBUFFERSIZE);
strcpy(listofdetails[0], "cars");
printf("%s\n", listofdetails[0]);
free(listofdetails[0]); // delete string
free(listofdetails); // delete string-array

assignment4.c:42:19: warning: assignment makes integer from pointer without a cast [enabled by default]
comes from the line
listofdetails[1] = "cars";
listofdetails is an expression of type char *; listofdetails[1] is an expression of type char, which is an integral type, and it evaluates to the second element of the array that listofdetails points to. "cars" is an expression of type char * (more on that later), and you can't assign pointer values to integers without a cast.
This boils down to what listofdetails is supposed to store. Is it suposed to store a single string? If so, then you would need to write
strcpy( listofdetails, "cars" );
in order to copy the contents of the string literal "cars" to the memory listofdetails points to.
If it's supposed to store a pointer to an existing string or string literal, then you would skip the malloc step altogether and simply write
char *listofdetails = "cars";
The string literal "cars" is stored as a 5-element array of char such that it is allocated when the program starts up and released when the program exits. An array expression will be converted ("decay") to a pointer expression unless it is the operand of the unary & or sizeof operators, or is a string literal being used to initialize another array in a declaration.
In the case above, "cars" isn't the operand of the sizeof or unary & operators, and it isn't being used to initialize an array of char, so it decays to a char *, and its value is the address of the first character in the string. So by the time this is done, listofdetails points to the string literal "cars".
If it's supposed to store a list of pointers to strings, then you would need to do the following:
char **listofdetails = malloc( sizeof *listofdetails * 40 ); // note extra level of indirection
This will allocate enough memory to store 40 pointers to char; since the type of listofdetails is char **, the type of listofdetails[1] will be char *, so the following lines will work as you intend:
listofdetails[1] = "cars";
printf("%s \n", listofdetails[i] );
Making that last change will fix
assignment4.c:44:2: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat]
which is complaining about
printf("%s \n", listofdetails[1] );
since as currently written, listofdetails[1] has type char, which is promoted to int since printf is a variadic function, and %s expects the corresponding argument to have type char *.
One more thing; in C, arrays are 0-origin, so you'd use the index 0 to access the first element of the list, and index 39 to access the last one.

Related

Incompatible types when assigning to type char[32] from type 'char*'

I'm trying to set the parameters of the structure below:
typedef struct thread_args_s {
int idx;
int role;
int fifo_desc;
char client_fifo_name[FIFO_NAME_MAX_LENGTH];
char msg[MSG_MAX_LENGTH];
} thread_args_t;
I've a problem assigning thread_args_t->client_fifo_name.
The client_fifo_name is given by a concatenation of the strings CLIENT_FIFO_NAME_SUFFIX + i, using sprintf().
In detail:
int i;
char* name;
for(i=0; i<THREAD_COUNT-1; i++){
thread_args_t* prod_args = malloc(sizeof(thread_args_t));
prod_args->idx = i;
prod_args->role = PROD_ROLE;
prod_args-> fifo_desc = server_fifo;
sprintf(name, "%s%d", CLIENT_FIFO_NAME_SUFFIX, i);
//How to assign the string "name" to prod_args->client_fifo_name?
prod_args->client_fifo_name = name;
[...]}
Compiling, the error is:
Incompatible types when assigning to type char[32] from type char*.
How can I fix it?
The types are incompatible because the left hand of the assignment is to exactly 32 characters, but the right hand of the assignment is a pointer. I'm guessing, but you probably want:
snprintf(prod_args->client_fifo_name,
FIFO_NAME_MAX_LENGTH,
"%s%d",
CLIENT_FIFO_NAME_SUFFIX, i);
The correct way to use name would be (here you have not allocated any memory to which the char* variable points to)
char *name = malloc(MAXLEN+1); Check the return value of malloc.
Or using an array
char name[MAXLEN+1];
After you did that - you will have to use strcpy to copy the content of the name to the designated array. Arrays are non-modifiable lvalue - assigning something to - it is error.
So after you make sure that destination has enough storage to store the string you are going to copy write
strcpy(prod_args->client_fifo_name , name);
To explain the error - here it finds the type mismatch in the line prod_args->client_fifo_name = name; here the left hand of assignment has type char [] and on the right it is char *. These mismatch of type in the assignment causes the error.
Also I just corrected the possible errors - you can omit allocating extra memory before copying to the actual one. You can directly use s(*)printf with the final target variable as buffer.
Incompatible types when assigning to type char[32] from type 'char*'
I've a problem assigning thread_args_t->client_fifo_name.
As prod_args->client_fifo_name in an array, it can not be assigned in C.
To assign a chracter array's elements, code may copy data with sprintf(), snprintf(), memcpy(), strcpy() or the like as answered by #Whilom Chime.
Code could assign each element of the array (a char) one at a time too, but let us avoid that.
snprintf() is a good choice, yet robust good also checks to see if data fits.
// sprintf(name, "%s%d", CLIENT_FIFO_NAME_SUFFIX, i);
// prod_args->client_fifo_name = name;
int count = snprintf(prod_args->client_fifo_name, sizeof prod_args->client_fifo_name,
"%s%d", CLIENT_FIFO_NAME_SUFFIX, i);
// Check for success
if (count < 0 || count >= sizeof prod_args->client_fifo_name) {
fprintf(stderr, "Not enough room or other error. Good-bye\n");
exit(EXIT_FAILURE);
}

Confused about the printing procedure of array of pointers to string

#include<stdio.h>
int main(){
char *names[2] = {"Lord", "Voldemort"};
printf("%s %s\n",names[0], names[1]);
return 0;
}
Why is the above code working? I mean, it should print the addresses of the strings it is containing in their respective indexes and we should be using *names[0] and *names[1]. But why it is working though?
If you had an array of integers like
int values[2] = { 1, 2 };
then what would you get if use used e.g. values[1]? You would get the second element in the array. Printing this values array would be done like
printf("%d %d\n", values[0], values[1]);
You are with me this far?
Now back your array. If you use names[1] what do you get then? You still get the second element in the array. And what is the second element? It is a pointer to char (i.e. char *). And what can a pointer to char be used as? A string.
And the "%s" format with printf expects a string, a char * more specifically. Which is just what you give as arguments.
If you use the dereference operator like *names[1] then thanks to operator precedence it is equal to *(names[1]) which is equal to names[1][0]. In other words it gives you the first character in the string pointed to by names[1].
names[0] and names[1] are both const char* types.
When you use %s with a const char* argument, printf outputs the characters starting at the beginning of the argument, until \0 is reached.
If you want the addresses then use
printf("%p %p\n", (const void*)names[0], (const void*)names[1]);

How to copy a char* into a char[][]

Before start, let me show you my code:
int main(int argc, char *argv[])
{
t_arbre *node;
char str[3][1];
&(*(str[0])) = strdup("1"); //lvalue required as left operand of assignment
str[1] = strdup("2"); //incompatible types when assigning to type ‘char[1]’ from type ‘char *’
str[2] = strdup("3");
if ((node = malloc(sizeof(t_arbre))) == NULL)
{
printf("Error: malloc in the main function failed\n");
return (-1);
}
create_node(node, str);
return (0);
}
So, as you can see, I'm currently working in C. And I'm trying to assign a (char*) to a (char[3][1]). Otherwise the compiler throw me for error:
incompatible types when assigning to type ‘char[1]’ from type ‘char *’
when I'm trying to assign by the following way:
str[2] = strdup("2");
I'm know that if I declare a string like this
char str[5];
and then try to assign it a string using for example strdup() function, it could trow me the same error. However in this case I know that I can "dereference" it like:
str[0]
Which will give me a (char) variable. And given I want it to store a string. I have to "transform" it into a (char*) by using the '&' charactere. Which will give me
&str[0]
In this case, it will work. because I have a pointer to the first character.
By doing so, I'll be able to copy a (char*) into a (char[]).
Otherwise, in the upper code I provide you, I want to copy a (char*) into a (char[3][1]) (Don't ask me why, it's a bit long to explain haha)
So as you can see, I tried my way to solve the error like
str[2] = strdup("2");
which throw me this error message
incompatible types when assigning to type ‘char[1]’ from type ‘char *’
And by this way
&(*(str[0])) = strdup("1"); //or &(*(str[0]))
which throw me this error message
lvalue required as left operand of assignment
Does anyone can tell me how can I copy a (char*) into a (char[][]) ?
Or is it just imposible to do what I want to do ?
I don't speak english very well, hopeing I used the right term.
Thank you :)
You can't assign to things that aren't intended for assignment, that's what "lvalue required as left operand of assignment" is telling you, because you're taking the address of something with &, which is essentially just a value, not somewhere you can store something (e.g. a variable), and then trying to assign to it.
A char* is not a char[], that's what the incompatible types error is about.
C arrays do not support assignment.
Don't forget that in C, arrays start at index 0, so the last valid index in an array of length 3 is 2 (e.g. arr[2]), not 3.
Use strcpy() instead to copy a string into an array:
char str[3][2]; // must allow space for the null terminator
strcpy(str[0], "1");
strcpy(str[1], "2");
strcpy(str[2], "3");
Or use an array of pointers and strdup():
char *str[3];
str[0] = strdup("1");
...
If you do that, don't forget to free them when you're done, because strdup() allocates memory, e.g.
// free one pointer from the array:
free(str[0]);
// or if you have allocated to every value in the array:
size_t arr_len = sizeof(str) / sizeof(*str);
for (size_t n = 0; n < arr_len; ++n)
free(str[n]);
strdup returns a pointer-to-a-char. If you want to store that pointer in an array, then you need an array of pointers, like this
char *str[3]; // an array of three pointer-to-char
str[0] = strdup("1");
str[1] = strdup("2");
str[2] = strdup("3");
for ( int i = 0; i < 3; i++ )
printf( "%s\n", str[i] );
If you want to copy the entire string content you can use strcpy, however note that it copies null terminated strings. It is needed to have place for the last null symbol. So, the length of string arrays must be at least 2 (char str[3][2]) to copy strings like "1".

C multidimentional char array - assignment makes integer from pointer without a cast

I create a big 2d char array and want to assign strings to it.
int i;
char **word;
int start_size = 35000;
word=(char **) malloc(start_size*sizeof(char *));
for(i=0;i<start_size;i++)
word[i]=(char *) malloc(start_size*sizeof(char));
word[2][2] = "word";
how do I assign a string?
Explain me why this code doesn't work...
I am new to low level programming and C but experienced in high level programming
You cannot do string assignment in C.
You need to call a function, sepcifically strcpy() (prototype in <string.h>)
#include <string.h>
strcpy(word[2], "word");
word[2][2] = "word";
In the above statement, the string literal "word" is implicitly converted to a pointer to its first element which has type char * whereas word[2][2] has type char. This attempts to assign a pointer to a character. This explains the warning message you have stated -
assignment makes integer from pointer without a cast
You can use string literals only to initialize character arrays. What you need to do is use the standard function strcpy to copy the string literal. Also, you should not cast the result of malloc. Please read this - Do I cast the result of malloc? I suggest the following changes -
int i;
int start_size = 35000;
// do not cast the result of malloc
char **word = malloc(start_size * sizeof *word);
// check word for NULL in case malloc fails
// to allocate memory
for(i = 0; i < start_size; i++) {
// do not cast the result of malloc. Also, the
// the sizeof(char) is always 1, so you don't need
// to specify it, just the number of characters
word[i] = malloc(start_size);
// check word[i] for NULL in case malloc
// malloc fails to allocate memory
}
// copy the string literal "word" to the
// buffer pointed to by word[2]
strcpy(word[2], "word");
You have to decide if you want a list of strings or a 2D array of strings.
A list of string works like this:
char **word;
word = (char**)malloc(start_size*sizeof(char*));
word[2] = "word";
In this example word[2] would be the third string in the list and word[2][1] would be the second character in the third string.
If you want a 2D array of string you have to do this:
int i;
char ***word;
^^^ 3 stars
int start_size = 35000;
word = (char***)malloc(start_size*sizeof(char**));
^^^ 3 stars ^^^ 2 stars
for(i=0;i<start_size;i++)
word[i] = (char**) malloc(start_size*sizeof(char*));
^^^ 2 stars ^^^ 1 star
word[2][2] = "word"; // no it works!
Note that in C you do not need the casts before the malloc. So this would also work:
word = malloc(start_size*sizeof(char**));

Strings and character with printf

I was confused with usage of %c and %s in the following C program:
#include <stdio.h>
void main()
{
char name[] = "siva";
printf("%s\n", name);
printf("%c\n", *name);
}
Output:
siva
s
Why we need to use pointer to display a character %c, and pointer is not needed for a string
I am getting error when I run
printf("%c\n", name);
I got this error:
str.c: In function ‘main’:
str.c:9:2: warning: format ‘%c’ expects type ‘int’, but argument 2 has type ‘char *’
If you try this:
#include<stdio.h>
void main()
{
char name[]="siva";
printf("name = %p\n", name);
printf("&name[0] = %p\n", &name[0]);
printf("name printed as %%s is %s\n",name);
printf("*name = %c\n",*name);
printf("name[0] = %c\n", name[0]);
}
Output is:
name = 0xbff5391b
&name[0] = 0xbff5391b
name printed as %s is siva
*name = s
name[0] = s
So 'name' is actually a pointer to the array of characters in memory. If you try reading the first four bytes at 0xbff5391b, you will see 's', 'i', 'v' and 'a'
Location Data
========= ======
0xbff5391b 0x73 's' ---> name[0]
0xbff5391c 0x69 'i' ---> name[1]
0xbff5391d 0x76 'v' ---> name[2]
0xbff5391e 0x61 'a' ---> name[3]
0xbff5391f 0x00 '\0' ---> This is the NULL termination of the string
To print a character you need to pass the value of the character to printf. The value can be referenced as name[0] or *name (since for an array name = &name[0]).
To print a string you need to pass a pointer to the string to printf (in this case name or &name[0]).
%c
is designed for a single character a char, so it print only one element.Passing the char array as a pointer you are passing the address of the first element of the array(that is a single char) and then will be printed :
s
printf("%c\n",*name++);
will print
i
and so on ...
Pointer is not needed for the %s because it can work directly with String of characters.
You're confusing the dereference operator * with pointer type annotation *.
Basically, in C * means different things in different places:
In a type, * means a pointer. int is an integer type, int* is a pointer to integer type
As a prefix operator, * means 'dereference'. name is a pointer, *name is the result of dereferencing it (i.e. getting the value that the pointer points to)
Of course, as an infix operator, * means 'multiply'.
The name of an array is the address of its first element, so name is a pointer to memory containing the string "siva".
Also you don't need a pointer to display a character; you are just electing to use it directly from the array in this case. You could do this instead:
char c = *name;
printf("%c\n", c);
If you want to display a single character then you can also use name[0] instead of using pointer.
It will serve your purpose but if you want to display full string using %c, you can try this:
#include<stdio.h>
void main()
{
char name[]="siva";
int i;
for(i=0;i<4;i++)
{
printf("%c",*(name+i));
}
}
The thing is that the printf function needs a pointer as parameter. However a char is a variable that you have directly acces. A string is a pointer on the first char of the string, so you don't have to add the * because * is the identifier for the pointer of a variable.
Or you can use %c like in the below code:
#include <stdio.h>
void main()
{
char name[]="siva";
//prints as string form
printf("%s\n",name);
//print each letter on different line
int size= sizeof(name);
int i;
for(i=0;i<size;i++){
printf("%c\n",name[i]);
}
}

Resources