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).
Related
#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]
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;
}
So I have an assignment to allocate enough memory to store a set of structs with different values in them. I am only allowed to call malloc once.
A have a struct that looks like this:
typedef struct ObjectTag Object;
struct ObjectTag
{
char *stringA[20];
char *stringB[30];
char *stringC[5];
unsigned short num;
};
For my malloc call I am doing
Object *myObjArray;
myObjArray= (Object*)malloc(numObjects * sizeof(Object));
I am trying to get information from an infile to place into my structs. Thus I am doing
fscanf(inFile, " %s", (*Object)[i].stringA);
fscanf(inFile, " %s", (*Object)[i].stringB);
fscanf(inFile, " %s", (*Object)[i].stringC);
fscanf(inFile, " %hu", (*Object)[i].num);
and so on in a loop.
But when I try to compile I get this error
format '%s' expects argument of type 'char *', but argument 3 has type 'char **'
and also this for the last one
format '%hu' expects argument of type 'short unsigned int *', but argument 3 has type 'int'
I have no idea what I'm doing wrong.
Notes that may be relevant:
The infile has an expected format to it
I have counted how many structs I needed as noted by the numObjects in the malloc call
char *stringA[20] is NOT a string of 20 (or 19) characters. It is an array of 20 strings of unspecified length. Are you sure this is what you want?
This question already has answers here:
format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘char (*)[64]
(3 answers)
Closed 5 years ago.
I don't know how to fix this warning, but especially why it appears in my code. In the first phase, my code has to record some names and surname and I used structures.
#include <stdio.h>
typedef struct STUDENT{
char surname[50];
char name[50];
} student;
int main()
{
student a[30];
int aux;
int i,j,n;
printf("Number of students: ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf("Surname:");
scanf("%s",&a[i].surname);
printf("Name:");
scanf("%s",&a[i].name);
}
return 0;
}
&a[i].surname is actually giving the address of struct member array surname. surname is of type char [50] so it's address will be of type char (*)[50]. As an argument to a function, array decay to pointer to it's first element. So, a[i].surname will do the job. You need to remove & from the argument.
printf("Surname:");
scanf("%s",a[i].surname);
printf("Name:");
scanf("%s",a[i].name);
Do not use & in strings as surname is already in format scanf is expecting it.
printf("Surname:");
scanf("%s",a[i].surname);
printf("Name:");
scanf("%s",a[i].name);
Also, please read why you have to set length for string in scanf.
Read a string as an input using scanf
scanf is looking for a pointer to char, but in your code you've got this
scanf("%s",&a[i].name);
a[i].name is an array of char which for the purposes of scanf is the same as a char *, but you're getting the pointer to it, so you end up with char (*)[50]. Just remove the unneeded ampersand and you'll remove the warning and fix your code.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I don't understand why the following code doesn't work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
struct data
{
int age;
char name[20];
};
int main()
{
struct data element[2];
for (int j = 0; j < 2; j++)
{
element[j] = (struct data) malloc(sizeof(struct data));
printf("Enter fav number%d? \n", j);
scanf("d", &element[j].age);
printf("Enter fav word? \n");
scanf("s", &element[j].name);
}
printf("\nThis is what you entered:\n");
for (int k = 0; k < 2; k++)
{
printf("%d. Fav number: %d\n", k, &element[k].age);
printf("%d. Fav word: %s\n", k, &element[k].name);
}
return 0;
}
The compiler error says:
beispiele.c: In function ‘main’:
beispiele.c:199:51: error: conversion to non-scalar type requested
element[j] = (struct data) malloc(sizeof(struct data));
^
beispiele.c:201:3: error: too many arguments for format [-Werror=format-extra-args]
scanf("d", &element[j].age);
^
beispiele.c:203:3: error: too many arguments for format [-Werror=format-extra-args]
scanf("s", &element[j].name);
^
beispiele.c:208:3: error: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘int *’ [-Werror=format=]
printf("%d. Fav number: %d\n", k, &element[k].age);
^
beispiele.c:209:3: error: format ‘%s’ expects argument of type ‘char *’, but argument 3 has type ‘char (*)[20]’ [-Werror=format=]
printf("%d. Fav word: %s\n", k, &element[k].name);
^
cc1: all warnings being treated as errors
element[j] is not a pointer and is a member of the array so already it has memory allocated statically.
If you need to allocate memory then have array of pointers.
struct data *element[2];
There is no need for using malloc (the array allocates all the memory).
Note, using printf does not require the address of the variable, so the & must be omitted before the variable. You do with scanf, as you must pass the address of the variable to which you want to write so that it can be modified (note the %d and %s in the scanf too). However, with the char[20], you do not need the & as the array is a pointer to the begin of the sequence of 20 characters.
int main()
{
struct data element[2];
for (int j = 0; j < 2; j++)
{
printf("Enter fav number%d? \n", j);
scanf("%d", &element[j].age);
printf("Enter fav word? \n");
scanf("%s", element[j].name);
}
printf("\nThis is what you entered:\n");
for (int k = 0; k < 2; k++)
{
printf("%d. Fav number: %d\n", k, element[k].age);
printf("%d. Fav word: %s\n", k, element[k].name);
}
return 0;
}
You have several problems:
Format specifiers start with a % sign. So change
scanf("d", &element[j].age);
to
scanf("%d", &element[j].age);
and
scanf("s", &element[j].name);
to
scanf("%s", element[j].name);
Wondering why I removed the & from the above scanf? It is because array names gets converted to a pointer to its first element.
These
printf("%d. Fav number: %d\n", k, &element[k].age);
printf("%d. Fav word: %s\n", k, &element[k].name);
should be
printf("%d. Fav number: %d\n", k, element[k].age);
printf("%d. Fav word: %s\n", k, element[k].name);
because the %d in the printf expects the value(int) and not the address of the variable(int*). Similarly, %s expects a char*, not a char(*)[20]
The cast here is completely wrong and should be removed:
element[j] = (struct data) malloc(sizeof(struct data));
This is done because malloc returns void* which can be assigned to any pointer type without casting.
etc See other answers.
You're getting 3 types of errors:
beispiele.c:199:51: error: conversion to non-scalar type requested
element[j] = (struct data) malloc(sizeof(struct data));
Check the documentation for malloc - it returns a void pointer to the allocated memory, which you then try to cast to a struct. The struct is obviously not a pointer type, hence the error message.
To be precise, the error message tells you that you're trying to cast to a type that is not scalar (roughly and incorrectly speaking, that is not a "basic" language type). C-style cast is very permissive and would happily perform many casts, for example, a long long * to a long long, without even a warning.
Keep in mind that you should not cast the pointer you get from malloc.
Also, as others have pointed out, this statement:
struct data element[2];
declares and automatically allocates the element variable. By calling malloc, you're asking the compiler to allocate it again, dynamically. If you're confused about memory allocation, take a look here.
beispiele.c:201:3: error: too many arguments for format [-Werror=format-extra-args]
scanf("d", &element[j].age);
Format strings used by scanf and printf use format specifiers starting with the % symbol, which is missing in all your calls. In this specific call, your format string "d" contains 0 format specifiers, so scanf expects 0 variable addresses to store values in. But you provide 1 address, so the compiler complains for "too many arguments".
Also, note that scanf needs a the address of a variable because arguments are passed by value - if it took the variable itself instead, it couldn't store the data to be accessible after the scanf call returned. By contrast, printf does not need to modify variables, so it takes variables rather than their addresses.
^ beispiele.c:208:3: error: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘int *’ [-Werror=format=]
printf("%d. Fav number: %d\n", k, &element[k].age);
This error message is pretty self-explanatory. Refer to the previous point about printf's arguments.
malloc returns a pointer to the allocated data, not the actual data. You should not cast the result of malloc.
Fix the code accordingly:
struct data* element[2];
...
element[j] = malloc(sizeof(struct data));
...
free(element[j]);
malloc returns a pointer to allocated memory, but you cast the pointer to a struct data. This is what the compiler complains about
error: conversion to non-scalar type requested
Furthermore, you don't need to allocate memory at all, because you already did so by
struct data element[2];
So, when you drop the malloc line, this error should be gone.