How do I dereference pointers? - c

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

Related

scanf statement in c and pointers

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.

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.

C - Pointers within struct not affecting the code

I am trying to understand why this code works
#include<stdio.h>
struct identity {
int age;
char name[20];
} test;
int main(void) {
printf("Enter name: ");
scanf("%s", &test.name);
printf("Enter age: ");
scanf("%d", &test.age);
printf("NAME: %s", test.name);
printf("\nAGE: %d", test.age);
}
even if I define the struct this way:
struct identity {
int *age;
char *name[20];
} test;
No matter how I write it, it works. I can understand that it works this way, but why does it work if I use the pointers?I mean, shouldn't it require printf("NAME: %s", *test.name); and printf("\nAGE: %d", *test.age); so as to print the value held inside the address of test.name and test.age respectively?
Is this a wrong way to use pointers within a struct? Therefore it works because I actually don't use pointers?
Its because when you put * your age works as an array, and char name[20] works as 2D array. In C when you have some array[] or array2d[][] when you put somewhere array it is your first element array[0] and when you put array2d it is your first poem (array[0][]). You also can do *(array+1) and this is the same like array[1].
It occurs to me that an int will fit in the space of an int *, on today's computers, so you can put the int value in the address space of the int var, without corrupting the other values of the struct. I added this to main():
printf("\nsizeof int: %d", (int) sizeof(int));
printf("\nsizeof int*: %d", (int) sizeof(int *));
and got this output on my system:
sizeof int: 4
sizeof int*: 8
Seems to me that's why it's working when the pointer vars are used instead of vars themselves?
Like many other questions, if you paid attention to compiler warnings, it'd be clear to you. When you change both struct members to pointers, you do get following compiler warnings:
str.c:11:5: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char **’ [-Wformat=]
printf("NAME: %s", test.name);
^
str.c:12:5: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat=]
printf("\nAGE: %d", test.age);
What does those mean? So effectively you have changed it to 2D character array and a integer array (or int*). It still works because the starting address of them both remains the same still. So accessing a variable or a pointer just with starting address yields the same result. However, you do notice difference if you did something like,
test.age++
In case of age being an int, that increments the value by 1. In case age being an int* in increments the pointer to the next slot (sizeof(int) increment).

In C : how to pass an array of structures as a pointer [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to pass an array of struct using pointer in c/c++?
I have an array of structures and need to pass a pointer to the array to a function.
I get these compile warnings and it crashes at runtime:
test.c:35:5: warning: passing argument 1 of ‘displayArray’ from incompatible pointer type
test.c:20:6: note: expected ‘struct tagdata **’ but argument is of type ‘struct tagdata (*)[10]’
typedef struct tagdata{
char lastName[20];
char firstName[20];
int age;
} PERSON[10], *PPERSON[];
int genNumber();
void displayArray(PPERSON pPerson);
int main(){
PERSON personDetails;
int i;
char buf[20];
for (i = 0; i < 10; i++){
sprintf(buf, "Charlie%d", i);
strcpy(personDetails[i].firstName, buf);
sprintf(buf, "Brown - %d", i);
strcpy(personDetails[i].lastName, buf);
personDetails[i].age = genNumber();
}
displayArray(&personDetails);
exit(0);
}
void displayArray(PPERSON pPerson){
int i = 0;
while (i < 10){
printf("Last Name First Name Age\n");
printf("%s %s %d\n",
pPerson[i]->lastName,
pPerson[i]->lastName,
pPerson[i]->age);
i++;
}
}
int genNumber(){
int n;
n=random();
return(n);
}
I have a structure that is also array
Although there is no such thing as a "structure that is also array", you can make an array of structs. You should untangle the typedef and the declaration of a struct variable first, like this:
typedef struct {
char lastName[20];
char firstName[20];
int age;
} PERSON;
PERSON person[10];
Now you can use PERSON as a name of a type, declare variables of type PERSON, make pointers to them, pass arrays, and so on, as if it were a value of a built-in type, such as an int:
void displayArray(PERSON pPerson[], int count) {
int i = 0;
printf("Last Name First Name Age\n");
while (i < count){
printf("%s %s %d\n",
pPerson[i].lastName,
pPerson[i].lastName,
pPerson[i].age);
i++;
}
}
You should pass a void pointer and cast it to PERSON[10].
As you see yourself, you are not passing the pointer to the PERSON stuct but rather you are passing pointer to an array which itself contains the struct. They are not equal.
To make it work properly, pass a void pointer and an integer stating the number of elements in the array. When you receive it, it will help you to avoid reading array beyond its allocated memory.
Roughly written:
** whatever = * whatever[10]
So you probably just want
*PPerson
An array can be passed to functions as a pointer, so instead of attempting to pass as a pointer to an array (by the way, now PPERSON is defined as an array of pointer, which is not what you have) just pass the array as-is, and make PPERSON a normal pointer (i.e. typedef struct tagdata *PPERSON;).
Then you can use the "pointer" as a normal array in the function.
*PPERSON[]; Is this you really want to user or
you want something like this: typedef PERSON *PPERSON;

format '%s' expects argument of type 'char *'

#include <stdio.h>
int main(void)
{
int i,j,k;
char st;
printf("enter string\n");
scanf("%s", st);
printf("the entered string is %s\n", st);
}
Compiling above program gives me a warning:
warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat]
palindrom.c:8:1: warning: format '%s' expects argument of type 'char *', but argument 2 has type 'int' [-Wformat]
What am I doing wrong here?
This is what happens when I run it:
$ ./a.out
enter string
kiaaa
the entered string is (null)
Edit:
Here is another version of the code (made char st; into char *st):
#include <stdio.h>
int main(void)
{
int i,j,k;
char *st;
printf("enter string\n");
scanf("%s", st);
printf("the entered string is %s\n", st);
}
However, it behaves the same on runtime.
char st is a single character. Judging by the rest of your code, you probably intended to declare an array of characters:
char st[80];
scanf needs a pointer to char* to indicate you are scanning a string.
You are supplying a character that's allocated on the stack.
You either want to use a getchar() or make st a char array.
You have a type mis-match.
scanfis not type safe, You need to provide proper type. scanf enables you to get data from the input and you need to tell it what is the type of the data you want it to read. You ask it to read a string by specifying %s by provide it with a character variable.
You need an array:
#define MAX_LENGTH 256
char st[MAX_LENGTH];
As #Jerry rightly points out, You can just simple avoid all the hassle by using:
getline() instead of using scanf
st is type of char
&st is type of char *
Take care of the difference.
BTW, only one char cannot be used to store a string. Use char[] array.
As others have mentioned you want to create an array:
Change char st; to char st[10]; or whatever size array you want.
With the above change st is an array that has 10 individual elements that can hold a single char value.
char st is a character i.e it will store only one character try it like this
main()
char st [100];
scanf("%s",st);
just change these three lines and it will work it will except only single word strings
here you have declared the function as an int that is int main() keep it as main() and it will work
Use char *st; or an array like char st[50];.
When you complete the usage of a char pointer, you should deallocate the memory used by the pointer. This can be done using free(st); function.
EDIT : As you are printing string and if you are using pointer, you can do:
printf("the entered string is %s\n",st);
printf("the entered string is %s\n",*st); // This will work in both cases, if you use char *st or char st[50]

Resources