#include <stdio.h>
// this works
void print_stuff (void* buf) {
printf ("passed arg as buf*: %s\n", buf);
}
/* This works */
void print_stuff_3 (char* buf) {
printf ("passed arg as char*: %s\n", buf);
}
// this does not work
void print_stuff_2 (char** buf) {
printf ("%s\n", *buf);
}
int main () {
char s [] = "hi";
printf ("s = %s\n", s);
// these work
print_stuff (&s);
print_stuff_3 (&s);
// this results in a Segfault
print_stuff_2(&s);
return 0;
}
I am a bit confused about the way things are passed around in C. I feel like &s should be of type char**, but it behaves as if it is of type char* when passed to a function. Why does this behaviour happen?
In particular, print_stuff_2 segfaults, whereas I thought that print_stuff_3 would give an error.
EDIT: To clarify, I expected print_stuff(&s) and print_stuff_3(&s) to fail (while they succeed), while print_stuff_2(&s) fails, whereas I feel it should succeed.
You need to remember that strings are not fundamental types in C. They are arrays of characters. Therefore
char s [] = "hi";
makes s a char * (in terms of variable type), i.e. a pointer to the first character of a 3 character array (h, i and NUL).
So in order to pass a pointer to the string, you what to use your print_stuff_3, as printf()'s %s argument takes exactly that (a pointer to the string, i.e. a pointer to the first character). Call this with print_stuff_3(s).
print_stuff works because a pointer is a pointer. It will be translated to a void * pointer on calling print_stuff, then printf()'s %s will convert it back to a char *. Call this with print_stuff(s).
print_stuff_2 doesn't work because you are taking the address of where s is stored. Had you written char *s = "hi"; that would work if you used print_stuff_2(&s). You'd pass the address of the pointer, then dereference that (to get the value of the pointer, i.e. the pointer to the first character) in by using *buf. Except buf then would be a poor choice of name, as you would be passing a pointer to a pointer to characters.
The complication is as follows. As it is, you are doing &s which just returns s when you have
char s [] = "hi";
(see How come an array's address is equal to its value in C? ), but returns the address at which the pointer variable s is stored on the stack if you have:
char *s = "hi";
Taking the address of an array doesn't really make sense (so evaluates to the address of the first element). You need to use char *s = "hi"; if you want to take the address of the pointer.
In C, array names are decays to pointer to its first element when passed to a function in most cases. When passing s to the function print_stuff, s decays to pointer to h. No need to pass it with &. &s is of pointer to array (char (*)[3]) type, i.e, it is giving the address of the entire array s.
In function call
print_stuff_3 (&s);
your compiler should warn you
[Warning] passing argument 1 of 'print_stuff_3' from incompatible pointer type [enabled by default]
I feel like &s should be of type char**, but it behaves as if it is of type char* when passed to a function. Why does this behavior happen?
No. You thought wrong. &s is of type char (*)[3].
void print_stuff (void* buf) & void print_stuff_3 (char* buf) In both functions, buf is of char * taking address as argument. Which should be print_stuff (s) & print_stuff_3 (s) respectively as s is the base address of char array s. So you shouldn't pass &s which is address of s.
As the below function buf is of type char **, it will expect address of address like print_stuff_2(&s) provided your declaration is char *s = "hi",
void print_stuff_2 (char** buf) {
printf ("%s\n", *buf);
}
Related
I'm having some trouble passing a valid value to the qsort function but can't quite figure out what's going wrong with it. Here is what I have so far:
int main(void)
{
char* strings[4] = {"Onus", "deacon", "Alex", "zebra"};
printf("%zu\n", sizeof(strings));
qsort(strings, 4, 8, scmp);
}
int scmp(const void *p1, const void *p2)
{
printf("%s\n", (char*) p1);
return 0;
// ignore return value -- I'm just looking to print the string.
}
It just seems to print gibberish when I do this. Is this because qsort expects a value a pointer to a value and I'm passing it a pointer to a (char) pointer? What would be the correct way to reference it then?
It seems instead it should be: printf("%s\n", *(char* const*) p1); ? This is from some trial-and-error, though not sure why that works -- i.e., the *(char**).
For example, for passing an int I can do:
const int *v1 = p1;
But then a char* needs to be:
const char *s1 = *(char* const *) p1;
Why not just const char *s1 = (char*) p1; ?
strings is an array of pointers to char. The comparison function for qsort gets passed pointers to the two elements of the array that should be compared. Since the elements of the array are pointers to char, the arguments p1, p2 to scmp are pointers to (const) pointers to char, and should be cast to char ** (or rather char * const *).
What needs to be passed to printf is the pointer to char itself, so you have to dereference the argument to get that pointer. If you wanted to look at the individual characters of the string, you'd have to dereference again. There are two *s in the name of the type, so you have to apply * two times to get back to the underlying primitive type.
printf("The first character of the string is %c\n", **(char * const *)p1);
I'm confused about these errors. The str1 is a string that is being passed but I get the a warning at the compare and and error at the if statement
int stringcmp(void* str1, void* str2) {
int a = strlen(str1);
int b = strlen(str2);
int x;
if ( a < b ) {
x = a;
} else {
x = b;
}
int c = 0;
while ( c < x ) {
if (str1[c] < str2[c]) { //errors happen here
return 0;
}
if (str1[c] > str2[c]) {
return 1;
}
c++;
}
if ( a == x ) {
return 0;
}
return 1;
}
Your function receives void* arguments, so in the line you pointed you are dereferencing pointers to void and that is why you get the warnings. I am not sure why you are receiving the value not ignore as it ought to be because that means that you are assigning the value of a function that returns void, and that is not the case of strlen (which is the only one you are calling).
And you should also receive an error in the calls to strlen when passing to it a void* parameter.
So you have to change your function's signature to
int stringcmp(const char* str1, const char* str2);
to suppress the warnings and be able to call strlen on the strings.
Dereferencing void * makes no sense, ever. In C, void means "no type"/"nothing", if you have void *p;, what is *p supposed to be?
In C, void * is used as a generic pointer type, "pointer to anything". To use p above, you must cast it to the type of the object it is pointing at (passed in some other way, unbeknownst to the compiler). E.g.:
int i;
void *p = (void *) &i;
...
int j = *(int *)p;
You know what p points to, the compiler doesn't.
The type void * is often used to pass around opaque data, or to write generic functions (like qsort, it gets an array of unspecified elements and a function that compares them).
That said, as a (misguided) extension GCC allows pointer arithmetic on void *, so that p + 1 is like ((char *)p + 1), it points at the next char position.
Your error arises from the fact that you are attempting to use the array notation str1[c] on a void-pointer. To understand why this is wrong we need to look at what the array notation in C actually means.
Let us assume that we define char* str1. Here we have said that str1 is an address to some place in memory where there is a char.
To get the data that is stored on the address which str1 is referring to we can use *str1.
This is equivalent to saying: "Go to the address that str1 is holding and give me what is stored on that address".
When we use the array notation we can use str1[0], this will be a value fetched from a place in memory where there is an element of the same type that str1 was defined as. It is the same thing as saying *str1 (go to the address that str1 is pointing to and give me the value that is stored there).
An array is just a bunch of data stored in a sequence in memory and strings are just arrays of characters of exactly 1 byte in size stored immediately after one another.
When we say str1[1] we are telling the compiler to move by the size of the type that str1 was defined to be pointing at, in this case 1 byte(char), and then get us whatever is stored at that location. In the case of strings, this should be another char.
Now when we have defined str1 as void*, how would the compiler know how how much it should move in memory to get the next element in the array? Since void has no size it is impossible.
Hopefully you now understand what you need to change in this line to get rid of your errors
int stringcmp(void* str1, void* str2)
Please take a look at the following code. It tries to pass an array as a char** to a function:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
The fact that I can only get it to compile by explicitly casting &test2 to char** already hints that this code is wrong.
Still, I'm wondering what exactly is wrong about it. I can pass a pointer to a pointer to a dynamically allocated array but I can't pass a pointer to a pointer for an array on the stack. Of course, I can easily work-around the problem by first assigning the array to a temporary variable, like so:
char test[256];
char *tmp = test;
test[0] = 'B';
printchar(&tmp);
Still, can someone explain to me why it doesn't work to cast char[256] to char** directly?
test is an array, not a pointer, and &test is a pointer to the array. It is not a pointer to a pointer.
You may have been told that an array is a pointer, but this is incorrect. The name of an array is a name of the entire object—all the elements. It is not a pointer to the first element. In most expressions, an array is automatically converted to a pointer to its first element. That is a convenience that is often useful. But there are three exceptions to this rule:
The array is the operand of sizeof.
The array is the operand of &.
The array is a string literal used to initialize an array.
In &test, the array is the operand of &, so the automatic conversion does not occur. The result of &test is a pointer to an array of 256 char, which has type char (*)[256], not char **.
To get a pointer to a pointer to char from test, you would first need to make a pointer to char. For example:
char *p = test; // Automatic conversion of test to &test[0] occurs.
printchar(&p); // Passes a pointer to a pointer to char.
Another way to think about this is to realize that test names the entire object—the whole array of 256 char. It does not name a pointer, so, in &test, there is no pointer whose address can be taken, so this cannot produce a char **. In order to create a char **, you must first have a char *.
Because test is not a pointer.
&test gets you a pointer to the array, of type char (*)[256], which is not compatible with char** (because an array is not a pointer). This results in undefined behavior.
The type of test2 is char *. So, the type of &test2 will be char ** which is compatible with the type of parameter x of printchar().
The type of test is char [256]. So, the type of &test will be char (*)[256] which is not compatible with the type of parameter x of printchar().
Let me show you the difference in terms of addresses of test and test2.
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("x = %p\n", (void*)x);
printf("*x = %p\n", (void*)(*x));
printf("Test: %c\n", (*x)[0]);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
test[0] = 'B';
test2[0] = 'A';
printf ("test2 : %p\n", (void*)test2);
printf ("&test2 : %p\n", (void*)&test2);
printf ("&test2[0] : %p\n", (void*)&test2[0]);
printchar(&test2); // works
printf ("\n");
printf ("test : %p\n", (void*)test);
printf ("&test : %p\n", (void*)&test);
printf ("&test[0] : %p\n", (void*)&test[0]);
// Commenting below statement
//printchar((char **) &test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Output:
$ ./a.out
test2 : 0x7fe974c02970
&test2 : 0x7ffee82eb9e8
&test2[0] : 0x7fe974c02970
x = 0x7ffee82eb9e8
*x = 0x7fe974c02970
Test: A
test : 0x7ffee82eba00
&test : 0x7ffee82eba00
&test[0] : 0x7ffee82eba00
Point to note here:
The output (memory address) of test2 and &test2[0] is numerically same and their type is also same which is char *.
But the test2 and &test2 are different addresses and their type is also different.
The type of test2 is char *.
The type of &test2 is char **.
x = &test2
*x = test2
(*x)[0] = test2[0]
The output (memory address) of test, &test and &test[0] is numerically same but their type is different.
The type of test is char [256].
The type of &test is char (*) [256].
The type of &test[0] is char *.
As the output shows &test is same as &test[0].
x = &test[0]
*x = test[0] //first element of test array which is 'B'
(*x)[0] = ('B')[0] // Not a valid statement
Hence you are getting segmentation fault.
You cannot access a pointer to a pointer because &test is not a pointer—it's an array.
If you take the address of an array, cast the array and the address of the array to (void *), and compare them, they will (barring possible pointer pedantry) be equivalent.
What you're really doing is similar to this (again, barring strict aliasing):
putchar(**(char **)test);
which is quite obviously wrong.
Your code expects the argument x of printchar to point to memory that contains a (char *).
In the first call, it points to the storage used for test2 and is thus indeed a value that points to a (char *), the latter pointing to the allocated memory.
In the second call, however, there is no place where any such (char *) value might be stored and so it is impossible to point to such memory. The cast to (char **) you added would have removed a compilation error (about converting (char *) to (char **)) but it would not make storage appear out of thin air to contain a (char *) initialized to point to the first characters of test. Pointer casting in C does not change the actual value of the pointer.
In order to get what you want, you have to do it explicitly:
char *tempptr = &temp;
printchar(&tempptr);
I assume your example is a distillation of a much larger piece of code; as an example, perhaps you want printchar to increment the (char *) value that the passed x value points to so that on the next call the next character is printed. If that isn't the case, why don't you just pass a (char *) pointing to the character to be printed, or even just pass the character itself?
Apparently, taking the address of test is the same as taking the address of test[0]:
#include <stdio.h>
#include <stdlib.h>
static void printchar(char **x)
{
printf("[printchar] Address of pointer to pointer: %p\n", (void *)x);
printf("[printchar] Address of pointer: %p\n", (void *)*x);
printf("Test: %c\n", **x);
}
int main(int argc, char *argv[])
{
char test[256];
char *test2 = malloc(256);
printf("[main] Address of test: %p\n", (void *)test);
printf("[main] Address of the address of test: %p\n", (void *)&test);
printf("[main] Address of test2: %p\n", (void *)test2);
printf("[main] Address of the address of test2: %p\n", (void *)&test2);
test[0] = 'B';
test2[0] = 'A';
printchar(&test2); // works
printchar(&test); // crashes because *x in printchar() has an invalid pointer
free(test2);
return 0;
}
Compile that and run:
forcebru$ clang test.c -Wall && ./a.out
test.c:25:15: warning: incompatible pointer types passing 'char (*)[256]' to
parameter of type 'char **' [-Wincompatible-pointer-types]
printchar(&test); // crashes because *x in printchar() has an inva...
^~~~~
test.c:4:30: note: passing argument to parameter 'x' here
static void printchar(char **x)
^
1 warning generated.
[main] Address of test: 0x7ffeeed039c0
[main] Address of the address of test: 0x7ffeeed039c0 [THIS IS A PROBLEM]
[main] Address of test2: 0x7fbe20c02aa0
[main] Address of the address of test2: 0x7ffeeed039a8
[printchar] Address of pointer to pointer: 0x7ffeeed039a8
[printchar] Address of pointer: 0x7fbe20c02aa0
Test: A
[printchar] Address of pointer to pointer: 0x7ffeeed039c0
[printchar] Address of pointer: 0x42 [THIS IS THE ASCII CODE OF 'B' in test[0] = 'B';]
Segmentation fault: 11
So the ultimate cause of the segmentation fault is that this program will try to dereference the absolute address 0x42 (also known as 'B'), which your program doesn't have permission to read.
Although with a different compiler/machine the addresses will be different: Try it online!, but you'll still get this, for some reason:
[main] Address of test: 0x7ffd4891b080
[main] Address of the address of test: 0x7ffd4891b080 [SAME ADDRESS!]
But the address that causes the segmentation fault may very well be different:
[printchar] Address of pointer to pointer: 0x7ffd4891b080
[printchar] Address of pointer: 0x9c000000942 [WAS 0x42 IN MY CASE]
The representation of char [256] is implementation dependent. It is must not be the same as char *.
Casting &test of type char (*)[256] to char ** yields undefined behavior.
With some compilers, it may do what you expect, an on others not.
EDIT:
After testing with gcc 9.2.1, it appears that printchar((char**)&test) passes in fact test as value cast to char**. It is as if the instruction was printchar((char**)test). In the printchar function, x is a pointer to the first char of the array test, not a double pointer to the first character. A double de-reference x result in a segmentation fault because the 8 first bytes of the array do not correspond to a valid address.
I get the exact same behavior and result when compiling the program with clang 9.0.0-2.
This may be considered as a compiler bug, or the result of an undefined behavior whose result might be compiler specific.
Another unexpected behavior is that the code
void printchar2(char (*x)[256]) {
printf("px: %p\n", *x);
printf("x: %p\n", x);
printf("c: %c\n", **x);
}
The output is
px: 0x7ffd92627370
x: 0x7ffd92627370
c: A
The weird behavior is that x and *x have the same value.
This is a compiler thing. I doubt that this is defined by the language.
I have program
void alloc(char **p)
{
*p=(char*)malloc(sizeof(char)*3);
(*p)[0]='a';
(*p)[1]='f';
(*p)[2]='\0';
}
main()
{
char p[]="hrrgr";
alloc(&p);
printf("%s",p);
}
It prints nothing. Please explain this.
I know by passing char*p ; and alloc(&p) will do the trick. But the purpose of my question is to understand the output I am getting.
p is an array of 6 characters. Therefore p is of type char[6]. &p is then of type pointer to char[6] type, i.e., char (*)[6]. When you pass an array to a function, it evaluates to a pointer to its first element. Thus when you are passing a char (*)[6] type value to your alloc function, you are assigning a char (*)[6] type to a char ** type. They are incompatible types and have different pointer arithmetic. You can't make char (*)[6] behave like a char ** type, even by typecasting which will only suppress compiler warning.
This is not allowed: p is an array of 6 characters, not a char pointer. You should not treat &p as a char** pointer.
If you want to fix this code, declare p like char*, not as an array:
char *p="hrrgr";
alloc(&p);
Running demo on ideone.
&p is of type char (*)[6] but your function alloc expects an argument of type char **. You are passing wrong type parameter.
try this...
void alloc(char **p)
{
*p=(char*)malloc(sizeof(char)*3);
(*p)[0]='a';
(*p)[1]='f';
(*p)[2]='\0';
}
main()
{
char *p;
alloc(&p);
printf("%s",p);
}
When ever you declare an array then there will be continuous allocation of memory but here your are changing starting 3 elements memory which changes the whole location of array and printing garbage...
I'm trying to learn C now, I'm coming from Java and there is some stuff that is new to me.
I want to print a string and send an int and a string(char array) to another method. But I keep getting some errors that I don't know how to fix.
Would really appreciate if someone could take their time and explain to me what's wrong in my code. I'm quite disoriented at the moment with these pointers. When to use %s and %c when printing etc...
Code:
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
string = "hello!";
int *ptr;
sptr = &string;
ptr = &k;
printf("%s \n", &sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}
And the errors.
test.c: In function ‘main’:
test.c:8:9: warning: assignment makes integer from pointer without a cast
test.c:15:2: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char **’
tezt.c: In function ‘sendptr’:
tezt.c:8:8: error: incompatible types when assigning to type ‘char[6]’ from type ‘char’
Thanks for your time! :)
First functions solved.
Second function i get this..
tezt.c: In function ‘sendptr’:
tezt.c:5:2: error: invalid initializer
#include <stdio.h>
void sendptr(int *test, char *fname)
{
char fnamn[] = &fname;
int pt;
pt = *test;
printf("%p \n", test);
printf("%d \n", pt);
printf("%s \n", fnamn);
}
char string;
string = "hello!";
First problem: you're declaring string as a single char, not as an array. Also, you can only initialize the array to a string literal in a single statement.
char string[] = "hello!";
Second problem: sptr is a pointer-to-char, so it has to point to the first element of your string. Either of these will do:
char *sptr = string;
char *sptr = &string[0];
Then, when printing the string, just pass sptr directly.
printf("%s \n", sptr);
EDIT for your next question.
char fnamn[] = &fname;
You're trying to assign a char** (pointer to pointer to char) to an array. That just won't work. If you want to copy the string pointed to by fname into fnamn then you need to use a function such as strncpy.
char fnamn[MAX_STRING_SIZE];
strncpy(fnamn, fname, MAX_STRING_SIZE);
Having said that, if you just want to print the string, then print fname directly without copying it into your array first.
Here's a corrected version of the program with some annotation:
#include <stdio.h>
int main(void) // int and (void) for standard mains.
{
int k = 10;
char *string; // a C string is a char array, you need a pointer to point to it
char *sptr;
int *ptr;
string = "hello!";
sptr = string;
ptr = &k;
printf("%s \n", sptr); // no &. The %s format expects a char*.
printf("Sending pointer.\n");
// sendptr(ptr, sptr); // don't know what this function is, ignoring
return 0;
}
In C language, the & operator means you want to use the address of the variable (ie & = "the address of the variable").
int an_integer=2; // an_integer is a memory part where you want to store 2 ;)
printf("%d", &an_integer); // here you will print the address of the memory part where an_integer is stored (not 2, more something like 2510849).
The * operator in a declaration of variable means that you want to have a pointer to a memory part, when using it in the code, it means the "the value contained at the address of"
int an_integer=2;
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = &an_integer; // here you set the pointer ptr_integer to the address of an_integer
printf("%d", *ptr_integer); // here you print the value contained at the memory address stored in the ptr_integer
The [] operator means you want to store an array of something. In C, an array can be seen as a pointer to a memory space.
int an_integer[2]; // you declare an array of 2 integers
int *ptr_integer; // you declare a pointer to an integer
ptr_integer = (int *)an_integer; // here you set the value of the pointer to the address of the array, you have to cast it into an (int *) to avoid compilation warnings.
For a start, I would suggest changing:
char string;
to:
char *string;
It's pretty clear that you want the string variable to be a string rather than a single character.
In addition, you probably want to change the two lines:
sptr = &string;
printf("%s \n", &sptr);
to:
sptr = string;
printf("%s \n", sptr);
but you could equally well just pass string itself to printf.
As for the sendptr(ptr, sptr);, we can't help that much without knowing more details about it.
To fix your second function (from your edit), change:
char fnamn[] = &fname;
to:
char *fnamn = fname;
or just use fname directly. You don't have to make a copy of the pointer and the former is for things like:
char fnamn[] = "I am a string literal";
I thought it might be helpful to adding something about the difference between a char array and a pointer to a string.
In function1 below, the local variable stringPtr is a pointer to memory which contains the string "hello!". The memory containing this string will be located in a read-only section of the program. The compiler decides where to place the string "hello!" and ensures that your local variable is initialised with this memory address.
You can modify the pointer stringPtr and change it to point somewhere else. But you cannot modify the memory it points at.
Also, it is perfectly valid to use the array access notation stringPtr[2] even though it is a pointer.
In function2 the compiler will set aside 9 bytes of space on the stack for the local variable stringArray and it will ensure that this array is initialised with the string "Goodbye!". As this memory is on the stack you can modify the contents of the array.
#include <stdio.h>
void function1(void)
{
char *stringPtr = "hello!";
printf("The first char is %c\n", stringPtr[0]);
printf("The next char is %c\n", *(stringPtr+1));
// This would cause a segmentation fault, stringPtr points to read-only memory
// stringPtr[0] = 'H';
}
void function2(void)
{
char stringArray[] = "Goodbye!";
printf("The first char is %c\n", stringArray[0]);
}
int main(void)
{
function1();
function2();
return 0;
}
First of all, the return type for main should be int, not void. void main() is only well-defined if your compiler documentation explicitly lists it as a legal signature. Otherwise you invoke undefined behavior. Use int main(void) instead.
Secondly, it's time for a quick crash course on strings, arrays, and pointers.
Unlike Java, C doesn't have a dedicated string datatype; rather, strings are represented as sequences of char values terminated by a 0. They are stored as arrays of char. The string literal "hello" is stored as a 6-element array of char (const char in C++). This array has static extent, meaning it is allocated at program startup and held until the program terminates. Attempting to modify the contents of a string literal invokes undefined behavior; it's best to act as though they're unwritable.
When an array expression appears in most contexts, the type of the expression is converted from "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array. That's one of the reasons the string = "hello"; statement doesn't work; in that context, the type of the expression "hello" is converted from "6-element array of char" to "pointer to char", which is incompatible with the target type (which, being char, isn't the correct type anyway). The only exceptions to this rule are when the array expression is an operand of either the sizeof or unary & operators, or if it is a string literal being used to initialize another array in a declaration.
For example, the declaration
char foo[] = "hello";
allocates foo as a 6-element array of char and copies the contents of the string literal to it, whereas
char *bar = "hello";
allocates bar as a pointer to char and copies the address of the string literal to it.
If you want to copy the contents of one array to another, you need to use a library function like strcpy or memcpy. For strings, you'd use strcpy like so:
char string[MAX_LENGTH];
strcpy(string, "hello");
You'll need to make sure that the target is large enough to store the contents of the source string, along with the terminating 0. Otherwise you'll get a buffer overflow. Arrays in C don't know how big they are, and running past the end of an array will not raise an exception like it does in Java.
If you want to guard against the possibility of a buffer overflow, you'd use strncpy, which takes a count as an additional parameter, so that no more than N characters are copied:
strncpy(string, "hello", MAX_LEN - 1);
The problem is that strncpy won't append the 0 terminator to the target if the source is longer than the destination; you'll have to do that yourself.
If you want to print the contents of a string, you'd use the %s conversion specifier and pass an expression that evaluates to the address of the first element of the string, like so:
char string[10] = "hello";
char *p = string;
printf("%s\n", "hello"); // "hello" is an array expression that decays to a pointer
printf("%s\n", string); // string is an array expression that decays to a pointer
printf("%s\n", p); // p is a pointer to the beginning of the string
Again, both "hello" and string have their types converted from "N-element array of char" to "pointer to char"; all printf sees is a pointer value.
Here's a handy table showing the types of various expressions involving arrays:
Declaration: T a[M];
Expression Type Decays to
---------- ---- ---------
a T [M] T *
&a T (*)[M]
*a T
a[i] T
&a[i] T *
Declaration: T a[M][N];
Expression Type Decays to
---------- ---- ---------
a T [M][N] T (*)[N]
&a T (*)[M][N]
*a T [N] T *
a[i] T [N] T *
&a[i] T (*)[N]
*a[i] T
a[i][j] T
&a[i][j] T *
Remember that the unary & operator will yield the address of its operand (provided the operand is an lvalue). That's why your char fnamn[] = &fname; declaration threw up the "invalid initializer" error; you're trying to initialize the contents of an array of char with a pointer value.
The unary * operator will yield the value of whatever its operand points to. If the operand isn't pointing anywhere meaningful (it's either NULL or doesn't correspond to a valid address), the behavior is undefined. If you're lucky, you'll get a segfault outright. If you're not lucky, you'll get weird runtime behavior.
Note that the expressions a and &a yield the same value (the address of the first element in the array), but their types are different. The first yields a simple pointer to T, where the second yields a pointer to an array of T. This matters when you're doing pointer arithmetic. For example, assume the following code:
int a[5] = {0,1,2,3,4};
int *p = a;
int (*pa)[5] = &a;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
p++;
pa++;
printf("p = %p, pa = %p\n", (void *) p, (void *) pa);
For the first printf, the two pointer values are identical. Then we advance both pointers. p will be advanced by sizeof int bytes (i.e., it will point to the second element of the array). pa, OTOH, will be advanced by sizeof int [5] bytes, so that it will point to the first byte past the end of the array.
#include <stdio.h>
void main()
{
int k = 10;
char string;
char *sptr;
sptr = "hello!";
int *ptr;
ptr = &k;
printf("%s \n", sptr);
printf("Sending pointer.\n");
sendptr(ptr, sptr);
}