filename is supposed to hold an address of a character (36 bits in core2Duo), why we are putting a 'string' in it ?
The expression char* filename="file.txt";
is a valid expression. Reason is type of a string literals in C is char[N]
that can easily decay into char*
, and char[N]
and char*
are compatible. Hence you can assign string address to a char*
pointer variable like you are doing in this expression.
Why the compiler would not generate an error since you might be storing an address which can never exist?
Please read below three points:
No, in the expression char* filename="file.txt";
, filename
is assigned a valid address. Its conceptually something like (assuming address starts with 21):
filename 21 22 23 24 25 26 27 28 29
+---+ +------------------------------------+
|21 |---> |'f'|'i'|'l'|'e'|'.'|'t'|'x'|'t'|'\0'|
+---+ +------------------------------------+
filename pointing to string, a valid address.
and It don't gives any error or warning: try below code example:
example-1:
#include<stdio.h>
int main(int argc, char **argv){
char* filename = "filename.txt";
printf("%s", filename);
return 0;
}
Compile it:
:~$ gcc y.c -Wall -pedantic
~$ ./a.out
filename.txt
No error and waring, its compiling and executing perfectly.
Regarding you comment to my answer:
Strings in C
are bit complex data-structured then simple value variables like int
, char
, float
.
In case of basic data-types:
int i = 5; You are assigning value 5, to variable i
char c = 'A'; You are assigning value 'A' to char variable c.
float f = 5.5f; You are assigning value 5.5f to float variable f.
But for strings, when you do:
char* filename = "filename.txt";
Then you are actually assigning address of string "filename.txt"
to char* pointer variable filename
.
Whereas if you do:
char filename[] = "filename.txt";
// ^ notice [] in declaration
Then you are assigning string "filename.txt"; to an array of char filename[]
, here filename
type is char[]
.
To learn about more deferences in both declarations read: What does sizeof(&arr) return?
A string literal may give you value or address dependences in what context you use it. for example try: printf(" address: %p, value: %s", "Hello", "Hello");
- Compiler do not validates address but check syntax.
The compiler is not responsible to validate that a address is legal. Compiler transplants code and checks syntax errors(for example uncompilable type mismatch). Suppose if you assign a fake address to a pointer it won't give you a waring (if you correctly type casts address). Consider the below example:
example-2:
#include<stdio.h>
int main(int argc, char **argv){
char* filename = "filename.txt";
char* ptr = (char*)0x020202;
printf("%s %s\n", filename, ptr);
return 0;
}
Compile:
$ gcc y.c -Wall -pedantic
And it will not generates any error or waring. Because syntactically all is fine and valid.
(Whereas ptr
assigned a fake address that may not exists).
- Invalid address causes Undefined behavior at runtime
Well, its fine to compile example-2 code where ptr
is assigned a a fake address, and compiler don't generates any error/warning even with stick checking flags options: -Wall -pedantic
.
But executing this code is wrong. It try to access memory address assigning to ptr
in printf statement, And the program will behave abnormally (at different executing instance). In C
-Language standard its called: Undefined behavior.
When you executes this code OS (but not compiler) detects memory right violation by a process -- An invalid access to valid memory gives: SIGSEGV And access to an invalid address gives: SIGBUS. This may cause process terminate/crash with some segmentation fault and coredump.
To learn and know what can be happen when you access illegal memory read: strcat() implementation works but causes a core dump at the end.