Why does the following code terminate to a segmentation fault
why the alternate version i.e. commented code, does not? The two versions of the code look the same to me. What am I missing?
#include <stdio.h>
1
2 void get_input(char**); // void get_input(char*);
3
4 int main(void)
5 {
6 char name[20];
7 get_input((char**)&name); //get_input(name);
8 printf("%s", name);
9
10 }
11
12 void get_input(char** m)//get_input(char* m)
13 {
14 scanf("%s", *m); // scanf("%s", m);
15 }
name is an array of characters. Its type is char[20].
In certain cases arrays decay into pointers. This is not one of those cases.
The C standard specifically mentions that an argument of the address-of operator does not decay. The result of applying the address-of operator to an array name is, unsurprisingly, is the address of the array.
In this case &name has the type char (*)[20]. This type is very different from char**. The former describes a pointer that points to a memory location that contains 20 characters. The latter describes a pointer that points to a memory location which contains a pointer that points to another memory location that contains a character. You cannot cast one to the other and hope it will work.
The answer by n.m. is correct. But if you want to know where the problem occurs "under-the-hood", take a look at the following code:
#include <stdio.h>
void get_input(char**);
int main(void)
{
char name[20];
char* pname = name;
char** ppname = (char**)&name; //this is what you were passing to get_input
printf("Address of name: %d\n", name);
printf("Value of pname: %d\n", pname);
printf("Value of &name: %d\n", &name);
printf("Value of ppname: %d\n", ppname);
get_input(ppname);
printf("Input: %s\n", name);
}
void get_input(char** ppinput)
{
char* pinput = *ppinput;
printf("Value of ppinput: %d\n", ppinput);
printf("Value of pinput: %d\n", pinput);
// The next line of code causes SEGMENTATION FAULT because
// pinput is the value of name[0], which is garbage,
// so you don't own the memory it points to.
scanf("%s", pinput);
}
If you compile and run that, you will see output similar to this:
Address of name: 2358816
Value of pname: 2358816
Value of &name: 2358816
Value of ppname: 2358816
Value of ppinput: 2358816
Value of pinput: 1
Segmentation fault
Take a look at the address of name and compare that with the value of pname (the pointer to name) and the value of ppname (which is defined as a char**).
The OP was perhaps expecting that &name would return a pointer to pname (i.e. that &name returns a pointer to a pointer to the first char in the array). However, you can see that pname and ppname are the same! This is because the compiler interprets &name as a pointer to the array, which incidentally is at the same address as the first character in the array (which is what pname points to).
The get_input function is actually perfectly fine. If ppinput (which the OP called "m") were truly a pointer to a pointer to a char, the function would work as expected. The char** would be dereferenced to a char* and scanf would fill it without a problem.
But as shown above, ppname is actually a pointer to an array, which is the same as a pointer to the first element of that array. So ppname is, in effect, the same thing as pname. So in the OP's code, he was really passing a value that is effectively a char* to get_input, instead of a char**.
Then, when get_input dereferences ppinput, it gets the VALUE of the first character in the char[] array (which in my output happened to be 1) instead of a pointer to that value, which is what scanf expects.
The OP could do exactly what he was intending to do in his question by simply changing the line (from my code example):
char** ppname = (char**)&name;
to
char** ppname = &pname;
Now this value for ppname truly IS a pointer to a pointer, which is what the OP was expecting &name to be. After you make that change, you really will be passing a char** to get_input and the function will work as expected.
I hope that sheds more light on the issue. The important dogmatic points were already mentioned by n.m. but a practical note to take from this is that a reference to an array returns the same value as a pointer to the first element. I.e.
(int)&name is (unintuitively) the same as (int)name when name is declared as an array. I say "unintuitively" because if you are not familiar with c++ arrays, you might expect that &var would always return a different value than var, but as this example shows, that turns out to not be true for arrays.
(Note that above, I've used int for pointer values and likewise %d for printf. This is bad practice in terms of portability, but for this illustration it should work and get the point across.)
char ** is a pointer to a pointer.when you pass the address of the array,it has type char (*)[20] which is incompatible with parameter of type char**.This is how you can correct the code :
#include <stdio.h>
void get_input(char* m); // void get_input(char*);
int main(void)
{
char name[20];
get_input(name); //get_input(name);
printf("%s", name);
}
void get_input(char* m)//get_input(char* m)
{
scanf("%s", m); // scanf("%s", m);
}
Related
My question is about dereferencing a char pointer
Here is my code -
#define MAX 10
char s[80]="Hello";
int main(){
char *stackValue;
stackValue=&s;//here I assined the address of s to stackValue
if(!stackValue){
printf("No place for Value");
exit(1);
}
else{
printf("\n%s",*stackValue);//This doesn't work with * before it
printf("\n%s",stackValue);//This works properly
}
return 0;
}
In the above code I have assigned the address of S[] to stackValue and when I am printing *stackValue it doesn't work ,
But If I print only 'stackValue' That works.
When I do same thing with Integer
int main(){
int i=10, *a;
a=&i;
printf("%d",*a);//this gives the value
printf("%d",a)//this gives the address
return 0;
}
Is printing char pointer and integer pointer is different. When I use * in int value it gives the value but gives an error when I use it as a char pointer.
Help me out?
With the first code snippet:
stackValue=&s; is incorrect given s is already an array to char. If you write like that then stackValue becomes pointer to pointer to char (not pointer to char).
Fix that by changing to stackValue=s;
Also, again %s expect a pointer to char (NOT pointer to pointer to char) - that explains why this doesn't work
printf("\n%s",*stackValue); // this doesn't work
You need printf("\n%s",stackValue); instead.
With the second code snippet.
a=&i; is ok because i is a single int, NOT an array.
What you are trying to do is this:
int main(void)
{
char a_data = "Hello, this is example";
char *pa_stack[] = {a_data};
printf("We have: %s\n", *pa_stack);
}
The "%s" format specifier for printf always expects a char* argument.
so this is working and correct statement
printf("\n%s",stackValue);
and in first statement you are passing value so it will give you undefined behaviour.
main()
{
const char **a = {"string1","string2"};
printf("%c", *a); /* prints s */
printf("%s", a); /* prints string1 */
printf("%s", a+1);/* prints ng1 */
}
GCC v4.8.3 prints "%s" for the last printf, where as http://codepad.org/ prints "ng1".
I thought that the code will create an array of pointers to two strings and the base address assigned to a, which allows normal pointer arithmetic. but it seems that there is something wrong with the assumption.The first printf suggests that my assumption is wrong. can anyone explain why this behavior is observed? ( note that VS 2012 has thrown an error saying too many initalizers where as GCC has thrown a warning for incompatible pointer assignment). I am aware of the warning due to incompatible pointer assignment.
const char **a is not an array of pointer to two strings. It declares a to be a pointer to pointer to const char.
const char **a = {"string1","string2"}; //No memory is allocated to store string literals
will invoke undefined behavior and you may get either expected or unexpected results.
To declare a as an array of two pointers you need to change the declaration as
const char *a[] = {"string1","string2"};
The memory range in your program's stack looks like this: (notice that it is not allocated before assignment which is wrong)
char** a = {s, t, r, i, n ,g, 1, \0, s, t, r, i, n, g, 2, \0}
Therefore when you print the command:
printf("%c", *a);
You are dereferencing the first character of the string which is 's'.
On the other hand, when you print the command:
printf("%s", a);
you are printing a string that starts at pointer a and finishes at '\0'. That's why you see the output 'string1'.
Lastly, when you type "a+1" you increase the pointer in one step (example here: How to increment a pointer address and pointer's value?). in this case because char** is a pointer, and every pointer is 4 byte, the "+1" jumps 4 chars forward.
Therefore when you print the command:
printf("%s", a+1);
The printf starts at the pointer 'a' + 4 bytes and ends at '\0'. That's why the output is 'ng1'.
Hope it was clear enough.
This is due to the following peculiar initialization performed by GCC.
please see int q = {1,2}; peculiar initialization list. the statement const char **a = {"string1","string2"}; results in a being treated as if const char **a = "string1". this solves the mystery as *a would print 's', a would print string1.
#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);
}
I've been looking around for a solution to this, but haven't quite found one.
I've got a function which do some string manipulation (simplified):
void plr(char str, char *stro){
strcpy(*stro, str);
}
My issue lies in the fact that I cannot get my result out from the function:
int main(void){
//string and string out.
char str[25], stro[25];
printf("Something please: ");
scanf("%s", &str);
plr(str, &stro); // So basically stro would be the same as str.
printf("Copy succesfull, %s", stro);
return 0;
}
The whole idea is that I have the function pluralis, which would append pluralis to the string given and output it to stro. The whole string manipulation has been tested and works, if it's inside the main(), but I simply cannot get it to work with a function and the pointer. I could obviously leave it be, but what would I learn from that.
Is there something I need to consider when it's an array I point to, rather than a normal value of sorts.
Edit: Thanks for all the help, it has been solved. Greatly appreciated all!
You should be doing this:
void plr(char str[], char stro[])
{
strcpy(stro, str);
}
int main(void)
{
char str[25], stro[25];
printf("Something please: ");
scanf("%s", &str); //unsafe code
plr(str, stro);
printf("Copy succesfull, %s", stro);
return 0;
}
Please be very careful when using a pointer to an array or a string for more :
http://pw1.netcom.com/~tjensen/ptr/pointers.htm
Using scanf to get a string from the user is really a bad thing for more:
Disadvantages of scanf
No need to mess up that way with pointers ;)
blackbear#blackbear-laptop:~$ cat prova.c
#include <stdio.h>
#include <string.h>
void foo(char *strin, char *strout)
{
strcpy(strout, strin);
}
int main(void)
{
char a[100], b[100];
printf("What's a? ");
scanf("%s", a);
printf("What's b? ");
scanf("%s", b);
foo(a, b);
printf("a is \"%s\"\nb is \"%s\"\n", a, b);
}
blackbear#blackbear-laptop:~$ gcc prova.c
blackbear#blackbear-laptop:~$ ./a.out
What's a? abc
What's b? def
a is "abc"
b is "abc"
blackbear#blackbear-laptop:~$
Explaination:
This works because when you use the name of an array it decays to a pointer to its first element. So foo(a, b) actually is foo(&a[0], &b[0]). So, even if a and b are arrays, passing them to a function "converts" them to a pointer.
Quoting from here:
When you pass an array as an argument to a function, you really pass
a pointer to the array's first element, because the array decays to a
pointer.
and, a few lines below:
Decaying is an implicit &; array == &array == &array[0]. In English,
these expressions read “array”, “pointer to array”, and “pointer to
the first element of array” (the subscript operator, [], has higher
precedence than the address-of operator). But in C, all three
expressions mean the same thing.
Concluding, the problem in your code is just plr's prototype.
Look for array to pointer decay for more info about this phenomena. :)
Perhaps you need a pointer to a pointer, i.e. declare your function void plr(char str, char **stro)
I believe that you have to change the code to:
void plr(char* str, char *stro)
You want to pass in an array str, you have to use a pointer char *str.
I don't think you can pass arrays directly to functions.
if you declare char str[25]; the compiler reserves memory for the array, if you use char * it will just point to the first element in the array.
I hope this works!
Gr,
Dieter
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);
}