Strings in c programming - c

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

Related

String not assignable to char array in C

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).

Confusion about how char *s and char s[] works at low level

I know similar questions, like this question, have been posted and answered here but those answers don't offer me the complete picture, hence I'm posting this as a new question. Hope that is ok.
See following snippets -
char s[9] = "foobar"; //ok
s[1] = 'z' //also ok
And
char s[9];
s = "foobar" //doesn't work. Why?
But see following cases -
char *s = "foobar"; //works
s[1] = 'z'; //doesn't work
char *s;
s = "foobar"; //unlike arrays, works here
It is a bit confusing. I mean I have vague understanding that we can't assign values to arrays. But we can modify it. In case of char *s, it seems we can assign values but can't modify it because it is written in read only memory. But still I can't get the full picture.
What exactly is happening at low level?
char s[9] = "foobar"; This is initialization. An array of characters of size 9 is declared and then its contents receives the string "foobar" with any remaining characters set to '\0'.
s = "foobar" is just invalid C syntax. You cannot assign a string to a char array. To make s have the value foobar. Use strcpy(s,"foobar");
char *s = "foobar"; is also initialization, however, this assigns the address of the constant string foobar to the pointer variable s. Note that I say "constant string". A string literal is on most platforms constant. A better way of making this clear is to write const char *s = "foobar";
And indeed, your next assignment s[1]= 'z'; will not work because s is constant.
You need to understand what the expressions are actually doing, then it might come clear to you.
char s[9] = "foobar"; -> Initialize the char array s by the string literal "foobar". Correct.
s[1] = 'z' -> Assign the character constant 'z' to the second elem. of char array s. Correct.
char s[9]; s = "foobar"; -> Declare the char array a, then attempt to assign the string literal "foobar" to the char array. Not permissible. You can´t actually assign arrays in C, you can only initialize an array of char with a string when defining the array itself. That´s the difference. If you want to copy a string into an array of char use strcpy(s, "foobar"); instead.
char *s = "foobar"; -> Define the pointer to char s and initialize it to point to the string literal "foobar". Correct.
s[1] = 'z'; -> Attempt to modify the string literal "foobar", to which is s pointing to. Not permissible. A string literal is stored in read-only memory.
char *s; s = "foobar"; -> Declare the pointer to char s. Then assign the pointer to point to the string literal "foobar". Correct.
This declares array s with an initializer:
char s[9] = "foobar"; //ok
But this is an invalid assignment expression with array s on the left:
s = "foobar"; //doesn't work. Why?
Assignment expressions and declarations with initializers are not the same thing syntactically, although they both use an = in their syntax.
The reason that the assignment to the array s doesn't work is that the array decays to a pointer to its first element in the expression, so the assignment is equivalent to:
&(s[0]) = "foobar";
The assignment expression requires an lvalue on the left hand side, but the result of the & address operator is not an lvalue. Although the array s itself is an lvalue, the expression converts it to something that isn't an lvalue. Therefore, an array cannot be used on the left hand side of an assignment expression.
For the following:
char *s = "foobar"; //works
The string literal "foobar" is stored as an anonymous array of char and as an initializer it decays to a pointer to its first element. So the above is equivalent to:
char *s = &(("foobar")[0]); //works
The initializer has the same type as s (char *) so it is fine.
For the subsequent assignment:
s[1] = 'z'; //doesn't work
It is syntactically correct, but it violates a constraint, resulting in undefined behavior. The constraint that is being violated is that the anonymous arrays created by string literals are not modifiable. Assignment to an element of such an array is a modification and not allowed.
The subsequent assignment:
s = "foobar"; //unlike arrays, works here
is equivalent to:
s = &(("foobar")[0]); //unlike arrays, works here
It is assigning a char * value to a variable of type char *, so it is fine.
Contrast the following use of the initializer "foobar":
char *s = "foobar"; //works
with its use in the earlier declaration:
char s[9] = "foobar"; //ok
There is a special initialization rule that allows an array of char to be initialized by a string literal optionally enclosed by braces. That initialization rule is being used to initialize char s[9].
The string literal used to initialize the array also creates an anonymous array of char (at least notionally) but there is no way to access that anonymous array of char, so it may get omitted from the output of the compiler. This is in contrast with the anonymous array of char created by the string literal used to initialize char *s which can be accessed via s.
It may help to think of C as not allowing you to do anything with arrays except for assisting in a few special cases. C originated when programming languages did little more than help you move individual bytes and “words” (2 or maybe 4 bytes) around and do simple arithmetic and operations with them. With that in mind, let’s look at your examples:
char s[9] = "foobar"; //ok
This is one of the special cases: When you define an array of characters, the compiler will help you initialize it. In a definition, you may provide a string literal, which represents an array of characters, and the compiler will initialize your array with the contents of the string literal.
s[1] = 'z' //also ok
Yes, this just moves the value of one character into one array element.
char s[9];
s = "foobar" //doesn't work. Why?
This does not work because there is no assistance here. s and "foobar" are both arrays, but C has no provision for handling an array as one whole object.
However, although C does not handle an array as a whole object, it does provide some assistance for working with arrays. Since the compiler would not work with whole arrays, programmers needed some other ways to work with arrays. So C was given a feature that, when you used an array in an expression, the compiler would automatically convert it to a pointer to the first element of the array, and that would help the programmer write code to work with elements of the array. We see that in your next example:
char *s = "foobar"; //works
char *s declares s to be a pointer to char. Next, the string literal "foobar" represents an array. Above, we saw that using a string literal to initialize an array was a special case. However, here the string literal is not used to initialize an array. It is used to initialize a pointer, so the special case rules do not apply. In this case, the array represented by the string literal is automatically converted to a pointer to its first element. So s is initialized to be a pointer to the first element of the array containing “f”, “o”, “o”, “b”, “a”, “r”, and a null character.
s[1] = 'z'; //doesn't work
The arrays defined by string literals are intended to be constants. They are “read-only” in the sense that the C standard does not define what happens when you try to modify them. In many C implementations, they are assigned to memory that is read-only because the operating system and the computer hardware do not allow writing to it by normal program means. So s[1] = 'z'; may get an exception (trap) or a warning or error message from the compiler. (Ideally, char *s = "foobar"; would be disallowed because "foobar", being a constant, would have type const char [7]. However, because const did not exist in early C, the types of string literals do not have const.)
char *s;
s = "foobar"; //unlike arrays, works here
Here s is a char *, and the string literal "foobar" is automatically converted to a pointer to its first element, and that pointer is a char *, so the assignment is fine.

Integer warning for char pointer

Can someone help me understand why I would be getting "warning: cast to pointer from integer of different size" for the following two lines of code?
so I have a pointer to a string (char *string) and a double pointer (char **final) that needs to the store the address of the last char in string... I thought the following lines of code would work but I keep getting the error... How do I fix it?
char last = *string;
*final = (char *)last;
(char *)last
last is of type char. Casting it to a pointer means the numeric code of the character stored in last will be interpreted as an address. So if last contains A, then this will cause the value 65 to be interpreted as an address. (Assuming ASCII). The compiler is smart and indicates that this is probably not the behavior you intend.
If string is a pointer to the last character in the string, last is a copy of that character. Since it's just a copy of the value, it bears no relationship to the location in the original string. To save that pointer into what final points to, you should do:
*final = string;
To declare a variable you have to specify what type you want the variable to be, and then what you want to call the variable. If you want a variable of type "char", called "last", it can be achieved by the following syntax:
char last;
If you want a pointer to a variable of a certain data type, you add the asterisk symbol like so:
char *last;
Now you have a pointer that you can use to point at a place in memory which have to contain a char. If you are trying to create a "string" in c, that is nothing more but a series of char's, that are ordered consecutively in memory. You can use a char pointer to point at the first char in this series of char's, and then you can use specific functions that work on strings (for example strcpy or strlen), by giving this char pointer as input argument.
Now to your problem. Let's say you create a string like this:
char *str = "example";
what you have done is create a series of char's, namely
'e', 'x', 'a', 'm', 'p', 'l', 'e', '\0'
(where the '\0' is the NULL character that marks the end of the string. This is necessary for any functions working on strings to recognize where the string ends). The char pointer you have created called "str" points at the first char, that is 'e'. Remember, the pointer has the address of this char, and all the rest of the chars are stored in the address space following this first char.
To access a particular char in this string, you have to dereference the pointer "str". If you want the first char in the string, you do this:
char first = *char;
This will save the first char in a variable of type char called "first", that is in this case the letter 'e'. To get the second char you do this:
char second = *(char+1);
What you're actually doing is "reading" (dereferencing) the value that your char pointer "str" is pointing to + 1 step of size "char" in memory. In this example, this means that the variable of type char called "second" now contains (the ASCII-value representing) the second letter in the string, that is 'x'.
If you want the size of a string you can use the function strlen. The syntax is this:
int length = strlen(str);
where "str" is our char pointer that is pointing at the first char in our string (that is 'e'). strlen will return the length of the string, not including the NULL character '\0' that simply marks the end of the string. That means in our example, length will equal 7, since there are 7 letters in the word "example". If you want to extract the last letter of this string, now all you have to do is what we did before, but remember that indexing in C start at 0. This means that if you have a string of length 7, the last element of this string will be located at "index" 6. Thus, to get the last char of a string you have to do this:
char last = *(str+length-1);
or if you have not saved length to a variable of type int, you can do it like this instead:
char last = *(str+strlen(str)-1);
If you want a pointer, pointing to the last char of the string, you have to initialize a new char pointer and make it point to place (memory address) where the last char of "str" is located. By the same logic as before, this is given by the memory address of the char at "index" 6 of our original string "str". So you create a new pointer, and let that pointer point to this memory address like this:
char *last = str+strlen(str)-1;
Remember that you need to include the header file string.h at the top of your file like so:
#include <string.h>

initialization error in Structures

struct college
{
char name[30];
char course[30];
int fee;
};
struct college c1={"purnia","m.com",5000};
struct college c2;
int main()
{
struct college c2={"magadh","hazipur",5200}; //1
c2.name="magadh"; // 2
c2.course="fine arts"; // 3
c2.fee=3000; //4
strcpy(c2.name,"godda"); //5
}
The line 2 and 3 gives error as incompatible type assignment whereas 1 and 5 works fine.This happens only with String type members.Is it because arrays can not be assigned but then why does line 1 works well.
Thanks in advance.
Line 1 works because you're not initializing members with a pointer to a string, but you're initializing the array with that string content.
When you try to execute:
struct college c2={"magadh","hazipur",5200};
The compiler reserves in memory the space for the structure and inits the arrays name and course respectively with "magadh" and "hazipur". But when you code:
c2.name="magadh";
You're trying to create an initialized string, "magadh", in memory and then assign its address to the array c2.name.
While copying the new string to the array using strcpy() is perfectly legal.
The fields are arrays of char. You have to copy the chars into the array. Try something like strcpy(), as you did in line 5. You can't just assign a "string" like that.
Line 1 works because it's an initialization, not an assignment. The compiler gives it the value provided when it allocates space for it on the stack.
If the fields were of type char * (say you declared char *name), you could assign it with a string literal. But the meaning is different: It would make name point to the string literal "magadh". You could not modify the contents of this string since it was a string literal. For example, the following would result in undefined behaviour:
char *name = "magadh";
name[0] = 'n'; /* <-- undefined behaviour */
One reason this bad (other than C says it is) is that you don't know where the compiler puts the "magadh" in memory. It is allowed to put it in the code text section, which is not writable.
Notice the difference with the following:
char name[30] = "magadh";
name[0] = 'n'; /* <-- this is OK */
The name here resides on the stack as a local variable. It is an array of char, which is given its value (initialized) when the array is allocated. You can modify it because you are allowed to modify local variables, since they are on the stack.
In C, there really are no "strings". They are just contiguous chars somewhere that (hopefully) end in a null terminator '\0'. If you want to "assign" one (as in your line 2 and 3), you have to explicitly say to copy chars from source to destination, beginning to end. This is what the strcpy() library function is for.

Different uses of pointers(*) in C

I am currently learning C with http://c.learncodethehardway.org/book/ and we are supposed to figure out some weird things on our own.
First of all I found this webpage that has already helped me understand some things about functions and function definitions and pointers and their use.
Now the problem comes to when I see some "string" definitions.
Please correct me if these assumptions I am going to make are wrong:
char name[] = "John"; // creates an array of characters with these four letters + '\0'
A "string" is just an array of characters ending with '\0'.
I also read that a * before an identifier usually means that it is a pointer. For example:
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
If those assumptions are right, I don't understand what is going on here:
char *name = "John";
Is that a pointer to a string? Or is it another way of defining a string?? If so, is
char *name[] = "John";
the actual pointer to the "string"? (which is just an array of characters?).
EDIT
Reading all your answers and comments I must ask another thing. "type char *" is a pointer to a char, right?
This statement
char name[] = "John";
means that name is an array of characters that will contain the following sequence
{ 'J', 'o', 'h', 'n', '\0' }
In fact you could write
char name[] = { 'J', 'o', 'h', 'n', '\0' };
These records are equivalent.
As for this statement
char *name = "John";
then there are the following actions made by the compiler. It creates an array of type char[5] to store the string literal and then assigns the address of the first character of this array to pointer name. So name will contain the address of the first character of the string literal. Though string literals in C has types of non-const arrays you may not change them. So it would be better to write
const char *name = "John";
For this statement
char *name[] = "John";
the compiler shall issue an error becuase to initialize an array (except character arrays) there must be used a brace-init list. The valid record will look as
char *name[] = { "John" };
In this case the array would have only one element of type char * that would point to the first character of the string literal. The string literal itself would be placed in memory as an array of type char[5] by the compiler.
As for the difference between records
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
and
char *name = "John";
then in the first record there is a scalar object myNum, You have to apply operator & that to get its address.
While in the second record the string literal is an array. In expressions such this it is adjasted by the compiler to a pointer to the first element of the array. So you have no apply operator & for the string literal. The expression in the right side has already type char *.
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
The type of myNum is int, which contains integer.
The type of myNum_pointer is int *, which contains address of integer variables.
-----------------------------------------------------
variables: | myNum | myNum_pointer |
-----------------------------------------------------
address : | 0x12341234 | 0x12341238 |
-----------------------------------------------------
the & operator gets the address of operand. So, &myNum is equal to 0x12341234
So the variables are initialized like this:
variables: | myNum | myNum_pointer |
---------------------------------------------
address : | 0x12341234 | 0x12341238 |
---------------------------------------------
value : | 18 | 0x12341234 |
---------------------------------------------
Now
char *name = "John";
defines name as a pointer to the first character in the string. The assignment means that as soon as the program loads, the pointer is set to hold the address of where the string is stored. It put string literal in read only part.
pointers only hold an address, they cannot hold all the characters in a character array. This means that when we use a char * to keep track of a string, the character array containing the string must already exist.
EX>
char name[] = "John";
char *name2;
name2=name;
name #2000
----------------------
| j | o | h | n | \0 |
----------------------
name2 #3000
--------
| 2000 |
--------
Also
For pointer to string array you can define it like
char * mystr[10];
After that you can initilize it by like
mystr[i]="john";
OR at define time also you can initialize like
const char *digitnames[] = {"zero", "one", "two", "three",
"four", "five", "six", "seven", "eight", "nine"};
char *name = "John";
defines an anonymous, statically allocated array of five bytes holding {'J', 'o', 'h', 'n', 0}, and declares a pointer name which initially points to the first element of the aforementioned array. That's the rule in C: an array "decays" into a pointer to its first element.
char *name[] = "John";
is invalid. It defines an array of char as before, but then tries to assign it to an array of char pointers, which makes no sense. The use case for char *[] is to store (pointers to the first char of) multiple strings:
char *names[] = {"John", "Mary"};
Read as: names is an array ([]), each element of which is a char*; this array we initialize with the elements "John" and "Mary", and since we're initializing pointers, these char arrays decay into pointers to their first elements.
Let's look at the line:
int myNum = 18;
In that line, you define a variable which has several properties:
Identifier : the variable name myNum
Type : int
Address : this is it's location in memory. For the purpose of this explanation, I'm giving it a value of 0xa1, but it could be any value of the sort.
Value: 18
In order to get a variable's address, you use the & operator. In this case, the line:
int *myNum_pointer = &myNum;
On the right hand side, &myNum returns the address of myNum, which in our case evaluates to 0xa1. And we are storing that in a variable called myNum_pointer, which has the type pointer-to-int, which means that it stores the address of an int variable. Because myNum_pointer is a variable in it's own right, it also has it's own properties:
Identifier : the variable name myNum_pointer
Type : int* (pointer-to-int)
Address : it's own location in memory. let's say it's 0xa2.
Value: 0xa1 (the address of myNum).
So, yes, you do need the & operator.
As for the part about the string: Don't define a string in C in this way.
char name[] = "John"; // Good
char *name = "John"; // Bad
This is because although arrays and pointers are related, they are not the same thing. Some compilers will warn you that the second statement is deprecated in C.
And finally,
char *name[] = "John";
Is incorrect. Because here you are saying the name is an array of pointers to characters, when it's just an array of characters.
"John" is actually a string literal, which is an array of {'J', 'o', 'h', 'n', 0}, where 0 is the null-termination character which signifies the end of a string in C. In fact, without the last 0, {'J', 'o', 'h', 'n'} would simply be an array of characters, and not a proper string, which is another important distinction.
I guess that this is a duplicate of hundreds of other qustions, but I'hm going to answer it anyway.
First, the '&' is a unary operator for the adress of a variable. So, for example, &foo could be an adress like 0xffff. So you definitely need the '&', because otherwise, if foo==1, your pointer would be on the adress 0x0001, and if you wanted to change the value, you would get a segfault (I guess it wouldn't even compile).
Second:
char* name="John";
does two things. It allocates an unchangable part in the memory and writes "John\0" into it. You have a pointer to that memory, but you can't change it, e.g write "john\0".
Third:
char* name[]
is a pointer to an array of chars. it can also be written like this:
char** name
or this:
char name[][]
It is actually an array of strings.
Fun fact: a '*' in front of a pointer gives back the value of the object the poiner points to. E.g:
int i=0;
int* pi;
pi=&i;
i==*pi //this is true
To answer your question of:
int myNum = 18;
int *myNum_pointer = &myNum; // do I need the '&'?
Yes, you need the & (which is the Address-of operator). This assigns the pointer myNum_pointer the address of myNum. If you take out the &, you are assigning the number in myNum directly to the pointer, which is a bad thing, and not what is intended. The problem would occur when you later use myNum_pointer, and it points to memory address 18 instead of the memory address of the myNum variable (if the compiler even accepts it). This would likely cause a segmentation fault at run time, which can be tricky to debug.

Resources