I try to assign a value to the second index of pointer, it gives me a warning
"[Warning] assignment makes integer from pointer without a cast"
and it doesn't run this program. I wonder, where am I making a mistake?
#include<stdio.h>
void main()
{
char *p="John";
*(p+2)="v";
printf("%s",p);
}
Firstly, In your code,
char *p="John";
p points to a string literal, and attempt to modify a string literal invokes undefined behavior.
Related, C11, chapter §6.4.5
[...] If the program attempts to modify such an array, the behavior is
undefined.
If you want to modify , you need an array, like
char p[]="John";
Secondly, *(p+2)="v"; is wrong, as "" denotes a string, whereas you need a char (Hint: check the type os *(p+2)). Change that to
*(p+2)='v';
To elaborate the difference, quoting C11, chapter §6.4.4.4, for Character constants
An integer character constant is a sequence of one or more multibyte characters enclosed
in single-quotes, as in 'x'.
and chapter §6.4.5, string literals
A character string literal is a sequence of zero or more multibyte characters enclosed in
double-quotes, as in "xyz".
Thirdly, as per the C standards, void main() should at least be int main(void).
You are assigning a pointer to a string literal to an element of another string literal.
First, you need to change the pointer and make it an array, so any modification is legal, this is an example
char p[] = "John";
then you need to replace "v" which is a string literal consisting of two characters 'v' and '\0', to 'v' which is the ascii value for the letter v as an integer
*(p + 2) = 'v';
also, this is the third element and not the second, because the first element is p[0].
You're making two mistakes.
First, you are attempting to modify the contents of a string literal; this invokes undefined behavior, meaning any of the following are possible (and considered equally correct): your code may crash, it may run to completion with no issues, it may run to completion but not alter the string literal, it may leave your system in a bad state, etc. Your compiler may reject the code completely, although I don't know of any compiler that does so.
If you want to be able to modify the contents of a string, then you need to set aside storage for that string, instead of just pointing to a string literal:
char p[] = "John"; // copies the contents of the string literal "John" to p
// p is sized automatically based on the length of the
// string literal
Here's a hypothetical memory map showing the result of that declaration and initialization:
Address Item 0x00 0x01 0x02 0x03
------- ---- ---- ---- ---- ----
0x8000 "John" 'J' 'o' 'h' 'n'
0x8004 0x00 0x?? 0x?? 0x?? // 0x?? represents a random byte value
...
0xfffdc100 p 'J' 'o' 'h' 'n'
0xfffdc104 0x00 0x?? 0x?? 0x??
The string literal that lives at 0x8000 should not be modified; the string that lives in p at 0xfffdc100 may be modified (although the buffer will only have enough space to store up to a 4-character string).
Your second mistake (and the one causing the compiler to complain) is in this line:
*(p+2)="v";
The expression "v" is a string literal and has type "2-element array of char"; since it's not the operand of the sizeof or unary & operators, the type "decays" to "pointer to char", and the value of the expression is the address of the string literal "v".
The expression *(p + 2) has type char (it resolves to a single character value), which is an integral type, not a pointer type. You cannot assign pointer values to non-pointer objects.
You can easily fix that by changing that line to
*(p + 2) = 'v'; // note single quote vs double quote
This time, instead of trying to assign the address of a string literal to p[2], you're assigning the value of a single character.
Related
I'm starting to understand pointers and how to dereference them etc. I've been practising with ints but I figured a char would behave similarly. Use the * to dereference, use the & to access the memory address.
But in my example below, the same syntax is used to set the address of a char and to save a string to the same variable. How does this work? I think I'm just generally confused and maybe I'm overthinking it.
int main()
{
char *myCharPointer;
char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);
myCharPointer = "This is a string.";
printf("%s\n", myCharPointer);
return 0;
}
First, you need to understand how "strings" work in C.
"Strings" are stored as an array of characters in memory. Since there is no way of determining how long the string is, a NUL character, '\0', is appended after the string so that we know where it ends.
So for example if you have a string "foo", it may look like this in memory:
--------------------------------------------
| 'f' | 'o' | 'o' | '\0' | 'k' | 'b' | 'x' | ...
--------------------------------------------
The things after '\0' are just stuff that happens to be placed after the string, which may or may not be initialised.
When you assign a "string" to a variable of type char *, what happens is that the variable will point to the beginning of the string, so in the above example it will point to 'f'. (In other words, if you have a string str, then str == &str[0] is always true.) When you assign a string to a variable of type char *, you are actually assigning the address of the zeroth character of the string to the variable.
When you pass this variable to printf(), it starts at the pointed address, then goes through each char one by one until it sees '\0' and stops. For example if we have:
char *str = "foo";
and you pass it to printf(), it will do the following:
Dereference str (which gives 'f')
Dereference (str+1) (which gives 'o')
Dereference (str+2) (which gives another 'o')
Dereference (str+3) (which gives '\0' so the process stops).
This also leads to the conclusion that what you're currently doing is actually wrong. In your code you have:
char charMemoryHolder = 'G';
myCharPointer = &charMemoryHolder;
printf("%s\n", myCharPointer);
When printf() sees the %s specifier, it goes to address pointed to by myCharPointer, in this case it contains 'G'. It will then try to get next character after 'G', which is undefined behaviour. It might give you the correct result every now and then (if the next memory location happens to contain '\0'), but in general you should never do this.
Several comments
Static strings in c are treated as a (char *) to a null terminated
array of characters. Eg. "ab" would essentially be a char * to a block of memory with 97 98 0. (97 is 'a', 98 is 'b', and 0 is the null termination.)
Your code myCharPointer = &charMemoryHolder; followed by printf("%s\n", myCharPointer) is not safe. printf should be passed a null terminated string, and there's no guarantee that memory contain the value 0 immediately follows your character charMemoryHolder.
In C, string literals evaluate to pointers to read-only arrays of chars (except when used to initialize char arrays). This is a special case in the C language and does not generalize to other pointer types. A char * variable may hold the address of either a single char variable or the start address of an array of characters. In this case the array is a string of characters which has been stored in a static region of memory.
charMemoryHolder is a variable that has an address in memory.
"This is a string." is a string constant that is stored in memory and also has an address.
Both of these addresses can be stored in myCharPointer and dereferenced to access the first character.
In the case of printf("%s\n", myCharPointer), the pointer will be dereferenced and the character displayed, then the pointer is incremented. It repeasts this until finds a null (value zero) character and stops.
Hopefully you are now wondering what happens when you are pointing to the single 'G' character, which is not null-terminated like a string constant. The answer is "undefined behavior" and will most likely print random garbage until it finds a zero value in memory, but could print exactly the correct value, hence "undefined behavior". Use %c to print the single character.
Why is it p+=*string[2]-*string[1] instead of p+=string[2]-string[1] (without asterisks)?
res[0]=*p; its value is 'c' why? Why p moves on the word letters while *string[1] moves among the words and not letters?
#####I have edited the code.........did "char* p=string;" can be replaced by "char p=*string[0];"?
The code's output is
c
int main (void)
{
char* strings[]={"abcdb","bbb","dddd"};
char*p=*strings;
char res[2];
p+=*string[2]-*string[1];
res[0]=*p;
p+=3;
res[1]=*p;
printf("%s\n",res);
return 0;
}
The program has undefined behaviour.
We will not take into account that there is a typo and instead of identifier strings there is sometimes used identifier string. Let's assume that everywhere in the code snippet there is used identifier strings.
In this statement
char*p=*strings;
the first element of the array is assigned to the pointer. The first element of the array is pointer to the first character of string literal "abc". So p points to character 'a' of the string literal.
In this statement
p += *strings[2] - *strings[1];
strings[2] is the third element of the array having type char * and its value is the address of the first character of string literal "dddd". Dereferencing this pointer *strings[2] you will get the first character of this string literal that is 'd'
strings[1] is the second element of the array having type char * and its value is the address of the first character of string literal "bbb". Dereferencing this pointer *strings[1] you will get the first character of this string literal that is `'b'
The difference between internal codes of characters 'd' and 'b' (for example in ASCII the code of character'b'is 98 while the code of'd'` is 100) is equal to 2.
So this statement
p += *strings[2]-*strings[1];
increases the pointer by 2. At first it pointed to character 'a' of the first string literal "abc" and after increasing by 2 it points now to character 'c' of the same string literal "abc".
Thus in this statement
res[0] = *p;
character 'c' is assigned to res[0].
After this statement
p+=3;
the value of p becomes invalid because it now points beyond the string literal "abc" and it is not necessary that the compiler placed string literal "bbb" exactly after string literal "abc".
So dereferencing this pointer in the next statement
res[1]=*p;
results in undefined behaviour.
According to the C Standard
If the result points one past the last element of the array object, it
shall not be used as the operand of a unary * operator that is
evaluated
It simply occured such a way that the compiler placed the string literals one after another in the memory. Though this is not guaranteed by the Standard.
So if after statement
res[1]=*p;
res[1] does not contain character '\0' then the next statement
printf("%s\n",res);
also has undefined behaviour.
First thing is there is nothing like string defined in your program, so your statement should be p+=*strings[2]-*strings[1]
Answer to both of your question is Dereferencing a pointer. You need to understand, how pointers work on Strings. Please check this link.
This question already has answers here:
How to declare strings in C [duplicate]
(4 answers)
Closed 8 years ago.
A few weeks ago I started learning the programming language C. I have knowledge in web technologies like HMTL/CSS, Javscript, PHP, and basic server administration, but C is confusing me. To my understanding, the C language does not have a data type for strings, just characters, however I may be wrong.
I have heard there are two ways of declaring a string. What is the difference between these two lines of declaring a string:
a.) char stringName[];
b.) char *stringName;
I get that char stringName[]; is an array of characters. However, the second line confuses me. To my understanding the second line makes a pointer variable. Aren't pointer variables supposed to be the memory address of another variable?
In the C language, a "string" is, as you say, an array of char. Most string functions built into the C spec expect the string to be "NUL terminated", meaning the last char of the string is a 0. Not the code representing the numeral zero, but the actual value of 0.
For example, if you're platform uses ASCII, then the following "string" is "ABC":
char myString[4] = {65, 66, 67, 0};
When you use the char varName[] = "foo" syntax, you're allocating the string on the stack (or if its in a global space, you're allocating it globally, but not dynamically.)
Memory management in C is more manual than in many other langauges you may have experience with. In particular, there is the concept of a "pointer".
char *myString = "ABC"; /* Points to a string somewhere in memory, the compiler puts somewhere. */
Now, a char * is "an address that points to a char or char array". Notice the "or" in that statement, it is important for you, the programmer, to know what the case is.
It's important to also ensure that any string operations you perform don't exceed the amount of memory you've allocated to a pointer.
char myString[5];
strcpy(myString, "12345"); /* copy "12345" into myString.
* On no! I've forgot space for my nul terminator and
* have overwritten some memory I don't own. */
"12345" is actually 6 characters long (don't forget the 0 at the end), but I've only reserved 5 characters. This is what's called a "buffer overflow", and is the cause of many serious bugs.
The other difference between "[]" and "*", is that one is creating an array (as you guessed). The other one is not reserving any space (other than the space to hold the pointer itself.) That means that until you point it somewhere that you know is valid, the value of the pointer should not be used, for either reading or writing.
Another point (made by someone in the comment)
You cannot pass an array as a parameter to a function in C. When you try, it gets converted to a pointer automatically. This is why we pass around pointers to strings rather than the strings themselves
In C, a string is a sequence of character values followed by a 0-valued byte1 . All the library functions that deal with strings use the 0 terminator to identify the end of the string. Strings are stored as arrays of char, but not all arrays of char contain strings.
For example, the string "hello" is represented as the character sequence {'h', 'e', 'l', 'l', 'o', 0}2 To store the string, you need a 6-element array of char - 5 characters plus the 0 terminator:
char greeting[6] = "hello";
or
char greeting[] = "hello";
In the second case, the size of the array is computed from the size of the string used to initialize it (counting the 0 terminator). In both cases, you're creating a 6-element array of char and copying the contents of the string literal to it. Unless the array is declared at file scope (oustide of any function) or with the static keyword, it only exists for the duration of the block in which is was declared.
The string literal "hello" is also stored in a 6-element array of char, but it's stored in such a way that it is allocated when the program is loaded into memory and held until the program terminates3, and is visible throughout the program. When you write
char *greeting = "hello";
you are assigning the address of the first element of the array that contains the string literal to the pointer variable greeting.
As always, a picture is worth a thousand words. Here's a simple little program:
#include <string.h>
#include <stdio.h>
#include <ctype.h>
int main( void )
{
char greeting[] = "hello"; // greeting contains a *copy* of the string "hello";
// size is taken from the length of the string plus the
// 0 terminator
char *greetingPtr = "hello"; // greetingPtr contains the *address* of the
// string literal "hello"
printf( "size of greeting array: %zu\n", sizeof greeting );
printf( "length of greeting string: %zu\n", strlen( greeting ) );
printf( "size of greetingPtr variable: %zu\n", sizeof greetingPtr );
printf( "address of string literal \"hello\": %p\n", (void * ) "hello" );
printf( "address of greeting array: %p\n", (void * ) greeting );
printf( "address of greetingPtr: %p\n", (void * ) &greetingPtr );
printf( "content of greetingPtr: %p\n", (void * ) greetingPtr );
printf( "greeting: %s\n", greeting );
printf( "greetingPtr: %s\n", greetingPtr );
return 0;
}
And here's the output:
size of greeting array: 6
length of greeting string: 5
size of greetingPtr variable: 8
address of string literal "hello": 0x4007f8
address of greeting array: 0x7fff59079cf0
address of greetingPtr: 0x7fff59079ce8
content of greetingPtr: 0x4007f8
greeting: hello
greetingPtr: hello
Note the difference between sizeof and strlen - strlen counts all the characters up to (but not including) the 0 terminator.
So here's what things look like in memory:
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
"hello" 0x4007f8 'h' 'e' 'l' 'l'
0x4007fc 'o' 0x00 ??? ???
...
greetingPtr 0x7fff59079ce8 0x00 0x00 0x00 0x00
0x7fff59879cec 0x00 0x40 0x7f 0xf8
greeting 0x7fff59079cf0 'h' 'e' 'l' 'l'
0x7fff59079cf4 'o' 0x00 ??? ???
The string literal "hello" is stored at a vary low address (on my system, this corresponds to the .rodata section of the executable, which is for static, constant data). The variables greeting and greetingPtr are stored at much higher addresses, corresponding to the stack on my system. As you can see, greetingPtr stores the address of the string literal "hello", while greeting stores a copy of the string contents.
Here's where things can get kind of confusing. Let's look at the following print statements:
printf( "greeting: %s\n", greeting );
printf( "greetingPtr: %s\n", greetingPtr );
greeting is a 6-element array of char, and greetingPtr is a pointer to char, yet we're passing them both to printf in exactly the same way, and the string is being printed out correctly; how can that work?
Unless it is the operand of the sizeof or unary & operators, or is a string literal used to initialize another array in a declaration, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", and the value of the expression will be the address of the first element of the array.
In the printf call, the expression greeting has type "6-element array of char"; since it isn't the operand of the sizeof or unary & operators, it is converted ("decays") to an expression of type "pointer to char" (char *), and the address of the first element is actually passed to printf. IOW, it behaves exactly like the greetingPtr expression in the next printf call4.
The %s conversion specifer tells printf that its corresponding argument has type char *, and that it it should print out the character values starting from that address until it sees the 0 terminator.
Hope that helps a bit.
1. Often referred to as the NUL terminator; this should not be confused with the NULL pointer constant, which is also 0-valued but used in a different context.
2. You'll also see the terminating 0-valued byte written as '\0'. The leading backslash "escapes" the value, so instead of being treated as the character '0' (ASCII 48), it's treated as the value 0 (ASCII 0)).
3. In practice, space is set aside for it in the generated binary file, often in a section marked read-only; attempting to modify the contents of a string literal invokes undefined behavior.
4. This is also why the declaration of greeting copies the string contents to the array, while the declaration of greetingPtr copies the address of the first element of the string. The string literal "hello" is also an array expression. In the first declaration, since it's being used to initialize another array in a declaration, the contents of the array are copied. In the second declaration, the target is a pointer, not an array, so the expression is converted from an array type to a pointer type, and the resulting pointer value is copied to the variable.
In C (and in C++), arrays and pointers are represented similarly; an array is represented by the address of the first element in the array (which is sufficient to gain access to the other elements, since elements are contiguous in memory within an array). This also means that an array does not, by itself, indicate where it ends, and thus you need some way of identifying the end of the array, either by passing around the length as a separate variable or by using some convention (such as that there is a sentinel value that is placed in the last position of the array to indicate the end of the array). For strings, the latter is the common convention, with '\0' (the NUL character) indicating the end of the string.
I am trying to learn pointers in C but is getting mixed up with the following concepts:
char *string = "hello"
char *string2;
What is the main difference between:
A.) *string2 = string;
then
B.) string2 = "bye";
Some pictures may help.
Assume the following memory map (addresses are completely arbitrary and don't reflect any known architecture):
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
"hello" 0x00501234 'h' 'e' 'l' 'l'
0x00501238 'o' 0x00
"bye" 0x0050123A 'b' 'y'
0x0050123C 'e' 0x00 0x?? 0x??
...
string 0x80FF0000 0x00 0x50 0x12 0x34
string2 0x80FF0004 0x?? 0x?? 0x?? 0x??
This shows the situation after the declarations. "hello" and "bye" are string literals, stored as arrays of char "somewhere" in memory, such that they are available over the lifetime of the program. Note that attempting to modify the contents of string literals invokes undefined behavior; you don't want to pass string literals (or pointer expressions like string that evaluate to the addresses of string literals) as arguments to functions like scanf, strtok, fgets, etc.
string is a pointer to char, containing the address of the string literal "hello". string2 is also a pointer to char, and its value is indeterminate (0x?? represents an unknown byte value).
When you write
string2 = "bye";
you assign the address of "bye" (0x0050123A) to string2, so our memory map now looks like this:
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
"hello" 0x00501234 'h' 'e' 'l' 'l'
0x00501238 'o' 0x00
"bye" 0x0050123A 'b' 'y'
0x0050123C 'e' 0x00 0x?? 0x??
...
string 0x80FF0000 0x00 0x50 0x12 0x34
string2 0x80FF0004 0x00 0x50 0x12 0x3A
Seems simple enough, right?
Now let's look at the statement
*string2 = string;
There are a couple of problems here.
First, a digression - declarations in C are centered around the types of expressions, not objects. string2 is a pointer to a character; to access the character value, we must dereference string2 with the unary * operator:
char x = *string2;
The type of the expression *string2 is char, so the declaration becomes
char *string2;
By extension, the type of the expression string2 is char *, or pointer to char.
So when you write
*string2 = string;
you're attempting to assign a value of type char * (string) to an expression of type char (*string2). That's not going to work, because char * and char are not compatible types. This error shows up at translation (compile) time. If you had written
*string2 = *string;
then both expressions have type char, and the assignment is legal.
However, if you haven't assigned anything to string2 yet, its value is indeterminate; it contains a random bit string that may or may not correspond to a valid, writable address. Attempting to deference a random, potentially invalid pointer value invokes undefined behavior; it may appear to work fine, it may crash outright, it may do anything in between. This problem won't show up until runtime. Even better, if you assigned the string literal "bye" to string2, then you run into the problem described above; you're trying to modify the contents of a string literal. Again, that's a problem that's not going to show up until runtime.
There are some subtle inferences being made by other answerers, missing the POV of a newbie.
char *string = "hello";
Declares a pointer variable which is initialized to point at a character array (a good type match traditionally).
The statement
*string = "hello";
dereferences what should be a pointer variable and assigns a value to the pointed location. (It is not a variable declaration; that has to be done above it somewhere.) However, since string has type char *—so *string has type char—and the right side of the assignment is an expression with a pointer value, there is a type mismatch. This can be fixed in two ways, depending on the intent of the statement:
string = "hello"; /* with "char *" expressions on both sides */
or
*string = 'h'; /* with "char" expressions on both sides */
The first reassigns string to point to memory containing a sequence of characters (hello\000). The second assignment changes the character pointed to by string to the char value h.
Admittedly, this is a slightly confusing subject which all C programmers go through a little pain learning to grasp. The pointer declaration syntax has a slightly different (though related) effect than the same text in a statement. Get more practice and experience writing and compiling expressions involving pointers, and eventually my words will make perfect sense.
*string can be read as "whatever string points to", which is a char. Assigning "bye" to it makes no sense.
A C string is just an array of characters. C string literals like "hello" above could be viewed as "returning" a pointer to the first element of the character array, { 'h', 'e', 'l', 'l', 'o' }.
Thus, char *string = "bye" makes sense while char string = "bye" doesn't.
char * is a pointer to a character. Literals such as "hello" returns a pointer to the first character of the string. Therefore, string = "bye" is meaningful making string point to the first character of string "bye".
*string, on the other hand, is the character pointed by string. It's not a pointer but an 8-bit integer. This is why the assignment *string = "bye" is meaningless and will probably lead to a segmentation fault as the memory segment where "bye" stored is read-only.
AFTER EDIT:
The difference is that A) will not compile, and if it did, it's undefined behavior, because you're dereferencing an uninitialized pointer.
Also, please don't change your question drastically after posting it.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the difference between char s[] and char *s in C?
Difference between char *str = “…” and char str[N] = “…”?
I have some code that has had me puzzled.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char* string1 = "this is a test";
char string2[] = "this is a test";
printf("%i, %i\n", sizeof(string1), sizeof(string2));
system("PAUSE");
return 0;
}
When it outputs the size of string1, it prints 4, which is to be expected because the size of a pointer is 4 bytes. But when it prints string2, it outputs 15. I thought that an array was a pointer, so the size of string2 should be the same as string1 right? So why is it that it prints out two different sizes for the same type of data (pointer)?
Arrays are not pointers. Array names decay to pointers to the first element of the array in certain situations: when you pass it to a function, when you assign it to a pointer, etc. But otherwise arrays are arrays - they exist on the stack, have compile-time sizes that can be determined with sizeof, and all that other good stuff.
Arrays and pointers are completely different animals. In most contexts, an expression designating an array is treated as a pointer.
First, a little standard language (n1256):
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type "array of type" is converted to an expression with type "pointer to type" that points to the initial element of the array object and is not an lvalue. If the array object has register storage class, the behavior is undefined.
The string literal "this is a test" is a 15-element array of char. In the declaration
char *string1 = "this is a test";
string1 is being declared as a pointer to char. Per the language above, the type of the expression "this is a test" is converted from char [15] to char *, and the resulting pointer value is assigned to string1.
In the declaration
char string2[] = "this is a test";
something different happens. More standard language:
6.7.8 Initialization
...
14 An array of character type may be initialized by a character string literal, optionally
enclosed in braces. Successive characters of the character string literal (including the
terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.
...
22 If an array of unknown size is initialized, its size is determined by the largest indexed element with an explicit initializer. At the end of its initializer list, the array no longer has incomplete type.
In this case, string2 is being declared as an array of char, its size is computed from the length of the initializer, and the contents of the string literal are copied to the array.
Here's a hypothetical memory map to illustrate what's happening:
Item Address 0x00 0x01 0x02 0x03
---- ------- ---- ---- ---- ----
no name 0x08001230 't' 'h' 'i' 's'
0x08001234 ' ' 'i' 's' ' '
0x08001238 'a' ' ' 't' 'e'
0x0800123C 's' 't' 0
...
string1 0x12340000 0x08 0x00 0x12 0x30
string2 0x12340004 't' 'h' 'i' 's'
0x12340008 ' ' 'i' 's' ' '
0x1234000C 'a' ' ' 't' 'e'
0x1234000F 's' 't' 0
String literals have static extent; that is, the memory for them is set aside at program startup and held until the program terminates. Attempting to modify the contents of a string literal invokes undefined behavior; the underlying platform may or may not allow it, and the standard places no restrictions on the compiler. It's best to act as though literals are always unwritable.
In my memory map above, the address of the string literal is set off somewhat from the addresses of string1 and string2 to illustrate this.
Anyway, you can see that string1, having a pointer type, contains the address of the string literal. string2, being an array type, contains a copy of the contents of the string literal.
Since the size of string2 is known at compile time, sizeof returns the size (number of bytes) in the array.
The %i conversion specifier is not the right one to use for expressions of type size_t. If you're working in C99, use %zu. In C89, you would use %lu and cast the expression to unsigned long:
C89: printf("%lu, %lu\n", (unsigned long) sizeof string1, (unsigned long) sizeof string2);
C99: printf("%zu, %zu\n", sizeof string1, sizeof string2);
Note that sizeof is an operator, not a function call; when the operand is an expression that denotes an object, parentheses aren't necessary (although they don't hurt).
string1 is a pointer, but string2 is an array.
The second line is something like int a[] = { 1, 2, 3}; which defines a to be a length-3 array (via the initializer).
The size of string2 is 15 because the initializer is nul-terminated (so 15 is the length of the string + 1).
An array of unknown size is equivalent to a pointer for sizeof purposes. An array of static size counts as its own type for sizeof purposes, and sizeof reports the size of the storage required for the array. Even though string2 is allocated without an explicit size, the C compiler treats it magically because of the direct initialization by a quoted string and converts it to an array with static size. (Since the memory isn't allocated in any other way, there's nothing else it can do, after all.) Static size arrays are different types from pointers (or dynamic arrays!) for the purpose of sizeof behavior, because that's just how C is.
This seems to be a decent reference on the behaviors of sizeof.
The compiler know that test2 is an array, so it prints out the number of bytes allocated to it(14 letters plus null terminator). Remember that sizeof is a compiler function, so it can know the size of a stack variable.
array is not pointer. Pointer is a variable pointing to a memory location whereas array is starting point of sequential memory allocated
Its because
string1 holds pointer, where pointer has contiguous chars & its
immutable.
string2 is location where your chars sit.
basically C compiler iterprets these 2 differently. beautifully explained here http://c-faq.com/aryptr/aryptr2.html.