scanf statement in c and pointers - c

I read many previous questions but none of them cleared my doubt.
When I define and initialize a pointer as
int a = 10;
int* p;
p = &a;
printf("%d", *p); // this will print the value of 'a' towards which p is pointing
But when I use scanf statement like-
int *p;
scanf("%d", &p);
printf("%d", p); // is this form of input similar to the one above?
Also when I use char pointer to read a string-
char* name[10];
scanf("%s", name);
printf("%s", name); // runs correctly.
What I know is that scanf expects pointer as input (like &a if it's like int a;)
But If I use--
char* names[5][10];
scanf("%s", names[1]); // reading the first name. Is this correct? because length of name can vary.
Now I am unable to print this, I tried no of ways.
A detailed explanation would be appreciated, my teacher isn't that good.
DOUBTS
When do we use * with a pointer? i.e. to print its value or for what?
Unable to scan char* xyz[a][b];
A brief explanation of my mistakes and the code above.
Edits-
int* arr[n];
for(int i =0; i<n; i++){
printf("Enter the salary of %d person:", i+1);
scanf("%d", &(arr[i]));
printf("\n");
}
Also, this type of assignment of value is not right?

printf("%d", p); // is this form of input similar to the one above?
no, %d expects an int argument, you're passing an int *. Supplying mismatched argument type for a conversion specifier invokes undefined behaviour.
That said, in case of
char* name[10]; // array of character pointers!
scanf("%s", name);
printf("%s", name); // runs correctly.
you're going wrong. Check the data types. %s expects the argument to be a pointer to a char array, so your code should be
char name[10]; // array of characters
scanf("%9s", name); // mandatory error check for success to be done.
printf("%s", name);
as, in most of the cases including this one, an array type decays to the pointer to the first element of the array, so while passing as function argument, name is actually of type char *.
Same goes with
char* names[5][10];
scanf("%s", names[1]);
changing that to
char names[5][10];
will suffice.

Related

How do I dereference pointers?

I am trying to make a C program that reads a person's name and age and passes both variables to a function as pointers. I am getting a few errors with what I have so far. I could use some clarification on what these errors mean.
warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘int *’ [-Wformat=]
9 | printf("Happy Birthday %s, you are now %d", name,age );
warning: assignment to ‘int *’ from ‘int’ makes pointer from integer without a cast [-Wint-conversion]
30 | age = atoi(digits);
My code so far:
#include <stdio.h>
#include <stdlib.h>
void happyBirthday(char * name, int * age){
int * newAge = age;
age = (newAge)++;
printf("Happy Birthday %s, you are now %d", name,age );
}
int main() {
char buffer[32];
char digits[3];
printf("Enter name:");
fgets(buffer,32,stdin);
printf("Enter age:");
fgets(digits,3,stdin);
char *name;
name = buffer;
int *age;
age = atoi(digits);
happyBirthday(name,age);
return 0;
}
Okay. The compiler is telling you that there are some problems in how you're using pointers, which is good (because your code was potentially dangerous). Let's look at what (I think) you wanted to do.
void happyBirthday(char * name, int * age){
int * newAge = age;
age = (newAge)++;
printf("Happy Birthday %s, you are now %d", name,age );
}
This function takes a char*, a pointer to a character, which is the usual way of passing a string, and is fine. The second parameter is an int*, or pointer to int, which is a good way of passing a value that you need to change. It is not needed if you just wanted the value of the age.
I'm guessing that your function was intended to increase the age of the person by one (since it's their birthday). This assumption is consistent with you passing the value "by reference", meaning as a pointer. Here's how I'd do that.
void happyBirthday(char* name, int* age){
(*age)++;
printf("Happy Birthday %s, you are now %d", name, *age );
}
The parameters are the same, although I removed some spaces to make it clearer to the reader that the type of name is char* and the type of age is int*.
The key change is how we increase the age with (*age)++;. Inside the parentheses we have *age which dereferences the pointer — meaning, it gets the integer that age is pointing to. This is, as we'll see later, the value stored as a local variable in the main function. After getting the value, we use the increment operator ++ to increase the age by one.
The other change to this code is that the parameter passed to printf again dereferences the pointer to get the value of the age variable, rather than its address (a number which isn't really useful to us in the context of birthdays).
Now let's fix up the main function.
int age;
age = atoi(digits);
happyBirthday(name,&age);
The first difference here is that we declare age to be an integer, rather than a pointer to an integer. This is consistent with atoi()'s return type, which is an int. It's the actual value of the age.
The second difference is that we use the address-of operator & to get a pointer to the variable age. Passing the address of the variable is what allows the function happyBirthday() to change the value.
age is an int* (an int pointer), not an int. If you want to retrieve the int it's pointing to, you need to dereference it using the * operator:
printf("Happy Birthday %s, you are now %d", name, *age);
/* Here ------------------------------------------^ */
You shouldn't have the * in int *age and you should take in a normal int instead of a pointer to an int in the function. The * next to the type means that it's a pointer to the type rather than the type itself, so like it points to some space in memory that contains that type.
You need it for the character array because it points to the start of the buffer and it'll start reading the string from that position when passed to printf, but you don't need it for age because atoi converts the string to a normal int type and the %d format reads normal ints.
There is no need to use int * in your case. Following code works perfectly
#include <stdio.h>
#include <stdlib.h>
void happyBirthday(char * name, int age){
int newAge = age;
age = (newAge)++;
printf("Happy Birthday %s, you are now %d", name,age );
}
int main() {
char buffer[32];
char digits[3];
printf("Enter name:");
fgets(buffer,32,stdin);
printf("Enter age:");
fgets(digits,3,stdin);
char *name;
name = buffer;
int age;
age = atoi(digits);
happyBirthday(name,age);
return 0;
}

Why doesn't C need '&' in scanf() while dealing with strings/char [duplicate]

This question already has answers here:
When should I use ampersand with scanf()
(3 answers)
Closed 2 years ago.
My code is very simple just basic IO. Now when I use this code it works perfectly.
#include <stdio.h>
int main()
{
int age = 0;
char name[100]; //Unlike c++ We need to specify char limit instead of "Name", so name can't go above 99 char + 1 terinator
printf("Enter your age: ");
scanf("%d", &age);
printf("Enter your name: ");
scanf("%s", name);// dont need & for char
printf("Your name is %s and your age is %d\n", name, age);
return 0;
}
Now
#include <stdio.h>
int main()
{
int age = 0;
char name[100]; //Unlike c++ We need to specify char limit instead of "Name", so name can't go above 99 char + 1 terinator
printf("Enter your age: ");
scanf("%d", &age);
printf("Enter your name: ");
scanf("%s", &name);// dont need & for char
printf("Your name is %s and your age is %d\n", name, age);
return 0;
}
when I make changes in line 10. and add &name. compiler throws this error. Why is that?
p2.c:10:17: error: format specifies type 'char *' but the argument has type 'char (*)[100]' [-Werror,-Wformat]
scanf("%s", &name);// dont need & for char
~~ ^~~~~
I don't know much about C.
Strings in C are simply sequences of characters. The %s format specifier thus expects a pointer to char such that it can write whatever scanf reads into the character sequence at the memory location pointed to by that pointer. In your case name is a character array and not a pointer, but in C you can often use arrays in contexts where pointers are expected, we say that the array decays to a pointer to its first member.
The scanf function takes a pointer of the variable whose value is to be set.
For other types like int, we use & operator which specifies the address of the variable whereas for char[] the variable name is converted to the pointer to the first element of the array so we don't need a &.
Strings are arrays of chars. Arrays are passed by reference in C.
So when you pass array to the function you actually pass the pointer.

How to convert int to char[] with sprintf() if char is pointer and the int not?

I likely don't understand the sprintf function.
char s[30];
int i;
scanf("%d",&i);
sprintf(s,i); /*->warning: makes pointer from int*/
sprintf accepts the target char[] as the first argument, and the rest of the arguments are the same as printf, or scanf's (format string first, then additional args if present).
So, in your case, it would simply be:
char s[30];
int i;
scanf("%d",&i);
sprintf(s, "%d", i);
For an input of 3, s would become '3'.
With sprintf(s, "%d%d", i, i);, it would become '33'.
The reason it tried to interpret i as a pointer in your example, was that it expected a (char) pointer (the format string).

Segmentation Fault in C Using Pointer to a Pointer

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);
}

array pointer function

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

Resources