String not assignable to char array in C - arrays

Hello I am very new to C and I have a simple question. Why does the second method of assigning a string to char name2[] not work? It causes a compilation error saying "Array type 'char[20]' is not assignable".
int main() {
char name[20] = "Alex";
char name2[20];
name2 = "Alex"; //error!
}

Why does the second method of assigning a string to char name2[] not work? It causes a compilation error saying "Array type 'char[20]' is not assignable".
There is no "second method" presented. This ...
char name[20] = "Alex";
... does not demonstrate an assignment, but rather an initialization. The = within is not functioning as the assignment operator, but rather as part of the syntax for specifying the initial value that name will take. And yes, this is a common source of confusion for newcomers to C.
On the other side, it is not possible to assign to whole arrays in C (this also is a common source of confusion for newcomers). This is the reason for the compilation error. You can copy the contents of one array into another with, for example, strcpy() or memcpy(), but there are almost no operators that accept arrays as operands. C arrays have more surprises to offer you, too, but I won't spoil them.
Once you understand C's idiosyncratic treatment of arrays, I think you'll see that it's internally consistent. Until then, however, you would do well to be alert whenever you see or use an array.

Arrays do not have the assignment operator. Instead you need to copy the string from one array to another like
#include <string.h>
//...
strcpy( name2, name );
Or just to copy the string literal using the same function strcpy
strcpy( name2, "Alex" );
On the other hand, you can assign the address of the string literal to a pointer like
char *name2;
name2 = "Alex";
In this case you may not change the string literal using the pointer.

Assuming you want to define a different string, and not just copy the previous one (assuming you used the same name as an example), you can use the scanf command:
#include <stdio.h>
int main()
{
char name[20] = "alex";
char name2[20];
printf("Type the name: \n");
scanf("%s", name2);
printf("name is %s. name2 is %s",name, name2);
return 0;
}
In this case it will be required an user input (you will need to write the name on the terminal).

Related

Printing a string using a pointer in C

I am trying to print a string read into the program from the user.
I need to be able to print the string by using a pointer.
Here is a simplified version of my code.
#include <stdio.h>
int main(void)
{
char string[100];
printf("Enter a string: ");
scanf("%s", string);
char *pstring = &string;
printf("The value of the pointer is: %s", *pstring);
return 0;
}
But I am getting a segmentation fault
Can someone please explain why this is happening?
You don't usually take an address of an array, it's either &string[0] or just string. In the printf() for %s you should pass a char pointer not a char (which is what *pstring is). It's a good idea to add a newline to the printf() format string as scanf() doesn't pass that along:
#include <stdio.h>
int main(void) {
char string[100];
printf("Enter a string: ");
scanf("%99s", string);
char *pstring = string;
printf("The value of the pointer is: %s\n", pstring);
return 0;
}
string IS a pointer. A constant one.
It is worth understanding what arrays are (compared to pointers).
And specifically the difference between those:
char *str1=malloc(6);
strcpy(str1, "hello")
char str2[6];
strcpy(str2, "hello");
In this example, str1 and str2 are both pointers.
But str1 is a variable (like "int x": x's value is stored in memory and you can modify it). Whereas str2 is not. It is a constant, like 12. It looks like a variable, because it is an identifier (str2), but it is not. Once compiled, there is no place in memory to store str2 value. The compiler computes its value, at compile time, and in the generated machine code, this value is inserted directly in the code. Exactly like for "12".
So str2=malloc(6) for example, or str2=whatever would make no sense. No more than typing 12=6 or 12=whatever. It is not a variable. It is a constant value.
And likewise, &str2 has no sense neither. No more than &12 has. It would be asking the address where a constant is stored. But a constant is not stored anywhere. It is a value directly in the code.
Namely str2 is a constant value of an address where the compiler has reseved enough room for 6 bytes. So you can store things in str2[0], str2[1], ..., str2[5], but not in str2 itself (again, it is a constant value, not a variable. You cannot store things in it, no more than you can store things in 12)
Situation for str1 is different. str1 is a variable, declared as type char *. You can store values of type char * in it (that is pointers to a char, that is memory address where a char is stored). And that declaration affect a default (initial) value to this variable, which is the address of 6 bytes, containing the letters 'h', 'e', 'l', 'l', 'o' and the terminal 0.
So, you can easily change str1, and store whatever pointer you want in str1. Writing str1=str2 for example.
So, long story short: both are pointers. str2 is a constant pointer, but still a pointer. Both are address of a place in memory where the first, then second, etc, char of the string are stored.
So, in your case, just type
char *pstring=string
or use string directly.
Or, for aesthetic purpose, to clarify that you mean "address of the first char of string", you may type
char *pstring = &(string[0])
which is the exact same thing as "string" (in C, syntax a[b] is just a shortcut to *(a+b), so &(string[0]) is &(*(string+0)), which is &*string which is string (another strange consequence of that, is that you could as well say
char *pstring = &(0[string])
again, that just means &(*(0+string))
Note that I advise none of those strange writing. But it helps understand how pointers are just values, that you may store in variables (like with str1) or use directly as constant in the code (like with str2). It is just less obvious than for integers (x a variable declared as int x=12; vs 12 that a constant) because in case of arrays (constant pointers) those values are named by the compiler and take the concrete appearance of an identifier in the code.

Why can't I use string functions like scanf() or gets() strcat() strcpy() with character pointer variables?

I don't see why I keep getting a segmentation fault when I try to use ANY string function with a character pointer variable. I am fully aware that fgets() is better to ensure no overwriting occurs but I am just trying to write a program to demonstrate how string functions actually overwrite data in memory addresses whereas re-declaring the pointer variable i.e pValues = "New Name"; will point to a completely different set of addresses (that contain your required characters).
I know fully well that string functions do seem to work with pointer constants i.e. when defined like this:
char values[ ] = "Name Here";
BUT WHY do they not work for pointer variables i.e when defined like this:
char *pValues[ ] = "Name Here";
this is the part that keeps failing...
#include <stdio.h>
#include <string.h> // required for strcpy(), strcat(), strlen()
main()
{
char *pName = "Peter Jones";
printf("The string pName is \'%s\'\n\n", pName);
// Now lets change it to a longer string with more litterals...
pName = "Dragons Den is GREAT!";
printf("\nThe string pName is %s\n", pName);
puts("Please enter a new string for pName ");
gets(pName);
printf("pName is now %s\n", pName); // THIS PRODUCES SEGMENTATION FAULT
return 0;
}
The book I am learning from has NO mention of dynamic memory or heap - which I haven't yet covered.
BUT WHY do they not work for pointer variables i.e when defined like this:
char *pValues[ ]= "Name Here" ;
Because pValues is not a character pointer. It is an array of character pointers. If instead you do this:
char *pValues = "Name Here" ;
most of the functions you want to use will work just fine. The one exception is any function that tries to write to any memory pointed to by this pointer:
puts("Please enter a new string for pName ");
gets(pName);
printf("pName is now %s\n", pName); // THIS PRODUCES SEGMENTATION FAULT
This part fails because gets() writes to a pointer that is pointing to a protected part of memory. You initialized it with:
char *pName = "Peter Jones";
so pName points to memory that holds a string literal. As you saw, attempting to write to this area of memory results in a segfault.
You will need to learn more about dynamic memory allocation and the heap in order to use gets() with a pointer.
"Why can't I use string functions like scanf() [etc.] with character pointer variables?"
You can, but only by following the rules:
the type defining the variable must be matched with the correct form of initializer.
string literal initializers to pointer variables create not editable variables
string literal initializers to char arrays are editable but not resizable.
The code example posted violates each of these.
This for example:
char values[] = "Name Here";
creates an editable C string with the implicit length set to sizeof("Name Here"). Because the size of the array is implicit (not specified), the initializer is required. If however the array size is explicit, the initializer is optional.:
//either line is legal, and both resulting variables are editable
char values[20];
char values2[20] = "Name Here";
This:
char *pValues[]= "Name Here";
Is an array of pointers to char, which expects an initializer list, which can be accomplished by surrounding the string literal(s) with {...}:
char *pValue[] = {"Name Here:"};
char *pValues[] = {{"Name Here:"},{"Address Here:"}};//see image
char *pValues2[] = {{"Name Here:"},{"Address Here:"}, ...};
resulting in from one to many non-editable C strings, each stored at a separate location in memory.
The expression:
char *pValue3 = "Name Here:"; //create non-editable variable
also places the contents of the string literal "Name Here:" into a memory location, and like the previous example, is in a non-writable area of memory. Once it is initialized at creation, it is no longer editable.
For example, given:
char *var1 = "this is a non-editable string";
char var2[80] = {"This is an editable string"};
strcpy(var1, var2);//is illegal
strcpy(var2, var1);//is legal
The following image corresponds to char *pValues[] above:
pName is a pointer. You have assigned it it with the reference to the string literal. String literals cannot be modified - thus segfault which is one of the possible outcomes of the invoked UB.
You need to allocate some space for the string.
you can:
char str[100];
pName = str;
/* or */
pName = malloc(100);
/*or even*/
pName = (char[100]){};
/* then */
fgets(pName, 100, stdin);
do not use gets function as it is dangerous.
Adrian, I do not see why you "keep getting a segmentation fault when I try to use ANY string function with a character pointer variable" either... And I do not know how to judge scanf() over fgets() to ensure anything.
But back to this issue in particular, maybe I can help you. There some more things you also need to be "fully aware" of:
When you write
char *pName = "Peter Jones";
you are defining a string literal. pName will then point to an area in memory that has "Peter Jones" in the successive addresses following pName. Yes, pName is in some sense a pointer to char, but it is a pointer pointing to a constant area. You can make pName point to another address but can not use it to change the "Peter Jones" area thing. It is there to stay.
So when you write
// Now lets change it to a longer string with more literals...
pName = "Dragons Den is GREAT!";
It will succeed... But maybe it should not. When you do this you are saying Goodbye to the string "Peter Jones". May be harmless but it is sort of a memory leak in the sense that it is there and it is lost.
But when you call gets() things are different: you are trying to write over a constant literal. You can not do that and you program is gone.
This has nothing to do with heap or stack or dynamic allocation. Just allocation. You need to have some writable area to point gets() to write to.
Example
char qName[40];
char* pName = "Peter Jones";
strcpy(qName, pName);
printf("The string pName is \'%s\'\n\n", pName);
// Now lets change it to a longer string with more litterals...
pName = "Dragons Den is GREAT!";
printf("\nThe string pName is %s\n", pName);
puts("Please enter a new string for qName ");
fgets(qName,10,stdin);
pName = qName;
// now pName points to the data read by gets()
printf("pName is now %s\n", pName);
Now it works. Declaring
char qName[40];
we have now 40 bytes available to use. qName is a pointer to an area of RAM of 40 contiguous bytes. In some sense it is a pointer to char.
But now you can tell gets() to read into qName. No problem here.
You can even point pName to qName. But then another area is lost: the area where "Dragons Den is GREAT!" is gone.
By the other hand, if you declare
char* p = NULL;
Now you have a pointer to char. It is now pointing to nothing, but at any time you can dynamically allocate memory and point p to that, ou make p point do an area of your program, like writing
p = qname + 2;
and then have p pointing to the third byte of qName.

C string setting character array to argv[1]

if I have a program as follows:
int main(int argc, char** argv) {
char s[32] = argv[1];
printf("entered char is %s\n", s);
}
Why do I get an error: array initializer must be an initializer list or string literal, during compile time?
Isn't argv[1] a string and isn't is legal to do
char s[32] = "A test string"
You can't initialize an array using a pointer like that. Instead you have to copy the string after declaration:
char s[32];
strcpy(s, argv[1]);
Note that you should really check if at least one argument is provided before doing that (by checking argc). Also note that unless you want to modify the string provided in the argument, there's really no need to keep a second copy of the string.
Oh and you might want to use strncpy instead of plain strcpy, to avoid a possible buffer overflow situation. Remember that strncpy will not terminate the string if the source is to long, so you need to do it explicitly.
Expression char s[32] = argv[1]; causes error because by doing s=argv[1] you are trying to change base address of s, which is not possible as s is constant pointer.
Use strcpy() to copy argv[1] into s
char s[32];
strcpy(s,argv[1]);
Asking a question like this means - you are not aware of certain rules. In C, there are a few possible ways you can initialize an array. And the compiler told you about that when it saw it violating the rule. It says it must be string literal or initializer list. The one you provided is not any of this. It is simply a pointer and you can't initialize an array by putting it in the right side of the = assignment operator.
char s[]="hello";
char s[]={'h','e','\0'};
Select one as shown above. First is using literal and second using initializer list. In your case you can't use any of these - what's the way? strcpy at your rescue. Before you use like the other answer showed make sure buffer is big enough to hold stuff you copy.

How do i determine the length of a string if it's declared as const char *str?

I have the following function structure
int function(const char *str)
{
return 0;
}
I never could fully understand why people use char *str rather than simply string str. So I am guessing this basically means that the argument is the pointer to the first character of the string. How do I determine the length of the string str given that argument?
What I've tried is to iterate through str, if I hit a NULL or "" or '', then that will be the end of it. However, none of these types are compatible for comparison. Please give me some clue regarding this. Thx!
Jamesdlin's answer is good, but to answer your question about comparisons, you would use '\0', IE:
char* a = "a";
int size = 0;
while (a[size] != '\0')
size++;
NULL is a pointer macro, "" is an empty character array (Though it has an implicit '\0', so you could theoretically do strcmp(a, "");), and '' is just an empty character, I'm not sure that it's even a valid statement.
Also, std::string is a C++ class and does not exist in the C standard library.
In C, strings are typically NUL-terminated. For NUL-terminated strings, you can simply call strlen(str).
I never could fully understand why people use char *str rather than simply string str.
There is no string type in C. You could add a typedef:
typedef char* string;
But adding typedefs for pointer types is generally a bad idea (because now you need a separate typedef for const char*; const string would not be the same thing).
And while doing so might seem like a good idea, in practice it will obscure your code since char*/const char* for strings is the norm.
You are almost correct, char *str is a pointer to the first character of a char array, but C has no predefined string type - it's just a zero-terminated char array. Instead of trying to write a function (although it would be a good student exercise), just call the library function in <string.h> with strlen (str); which takes a pointer to the character array. You don't pass *str or &str but just str if it is a declared array variable. If memory was allocated dynamically, you pass the allocated pointer, so if the pointer was declared as char *memstr you pass it as memstr. As others have said, it's best not to try to define a string, better to understand how the char array works.

Strings in c programming

why am i unable to compile the program containing the code
char name[10];
name= "Rajesh";
While i am able to compile a program with
char name[10]="Rajesh";
That's because your code snippet is not performing declaration, but assignment:
char name[10]; // Declaration
name= "Rajesh"; // Assignment.
And arrays are not directly assignable in C.
The name name actually resolves to the address of its first element (&name[0]), which is not an lvalue, and as such cannot be the target of an assignment.
String Variable Declarations and Assignments
String variables can be declared just like other arrays:
char phrase[14];
String arrays can be initialised or partially initialised at the same time as being declared, using a list of values enclosed in "{}" braces (the same is true of arrays of other data types). For example, the statement
char phrase[14] = {'E','n','t','e','r',' ','a','g','e',':',' ','\0'};
both declares the array "phrase" and initialises it to the state. The statement
char phrase[14] = "Enter age: ";
is equivalent. If the "14" is omitted, an array will be created just large enough to contain both the value ""Enter age: "" and the sentinel character "'\0'", so that the two statements
char phrase[] = {'E','n','t','e','r',' ','a','g','e',':',' ','\0'};
char phrase[] = "Enter age: ";
are equivalent both to each other and to the statement
char phrase[12] = "Enter age: ";
However, it is important to remember that string variables are arrays, so we cannot just make assignments and comparisons using the operators "=" and "==". We cannot, for example, simply write
phrase = "You typed: "; //Wrong way
Instead, we can use a special set of functions for string assignment and comparison.
Edited :
And other way is to do that, using pointer : -
Declare variable
char const *phrase; /* a pointer to type character */
And initialize variable as where you want, as
phrase = "Test string";
You cannot assign values to string arrays by using assignment.
In C, You can only initialize arrays not assign them, a array of characters is no exception for this rule.
You will need to use string copying functions like strcpy or strncpy and so on.
However you can encapsulate a string in a struct and simulate this:
typedef struct Yourstring Yourstring;
struct Yourstring
{
char a[24];
};
Yourstring a = { "abcd" };
Yourstring b = a;
Yourstring c = { 0 };
c = b;
char name[10];
In this first example, you're declaring name to be an array of ten characters. The symbol name is now interpreted as the starting address of this array, but while you can write into the array, you can't move the symbol name.
So, this:
name= "Rajesh";
would mean pointing name away from the array you declared and at the location of the string literal "Rajesh" which is stored elsewhere in memory. You just can't do this.
What you can do is either:
strcpy(name, "Rajesh");
which copies your string literal from it's immutable location in your executable, into the char array you declared, or:
char const *pointer_to_name = "Rajesh";
which doesn't copy anything, but merely stores the address of your immutable string literal into a variable where you can use it, or your second example:
char name[10]="Rajesh";
which declares name to be an array of 10 characters and initialises it.
char name[10];
name= "Rajesh";
Here name is an array of characters.
The simple name is basically pointer to first element of array and it cannot be assigned with some value like it's done in above statement.
My point is
char name[10];
name= "Rajesh";
Explanation:
This is not the correct declaration of array. Strings are nothing but collection of characters terminated with '\0' operator. So, the array index (which in this case is 'name', basically points to address of 1st character in array i.e name holds the address of character 'R' in 'Rajesh'.
If you want to initialize like as mentioned above, the better approach could have been:
char name[10];
*name= "Rajesh";
Now, the above declaration won't throw any error, but still it will throw warning, like:
assignment makes integer from pointer without a cast [-Wint-conversion]
*name = "Rajesh"
AS char name[10]="Rajesh" is definition compiler understands what are you trying to do and corrects your mistake. In c++ strings written in "" are constant and some compilers put them to stringpools to save space. name="...." means that you are trying to assign a constant to a non-constant pointer which is not allowed.
you should use strcpy to copy a string into an array.
char name[10] ="Rajesh";
This one is an array initialization. The compiler knows of it. It's a one-shot trick. You can use it only when you define your variable. It would be equivalent to:
char name[10] = { 'R', 'a', 'j', 'e', 's', 'h', '\0' };
The other one is illegal, because you can't use array initialization outside of array definition.
I dont remember where exactly i read it but C standard says, you can assign a string value for an array at the defination but not after the defination.
char a[10]="rajesh" its a defination hence works
char a[10];a="rajesh"; fails its not a defination
rather you need to use strcpy(a,"rajesh") to assing a value for a string, if its not a defination

Resources