I'm trying to compare a string stored in a structure. I'm using scanf to input a string and I need to search for the string in the structure. Here is the code I have:
int printing_airports(int all_routes_size,int all_airports_size){
int i,position;
char airport;
printf("Enter airport code: ");
scanf("%s", airport);
for(i=0;i<all_airports_size;i++){
if(strcmp(airport,all_airports_divid[i].code) == 0){
position = i;
}
}
printf("%s",all_airports_divid[position].code);
}
This is how I declared my structures
struct all_routes{
int id;
char departure_code[4];
char arrival_code[4];
};
struct all_routes all_routes_divid[500];
This is the error I'm getting when I tried to compile
y:~/enee150/project2: compile
functions.c: In function 'printing_airports':
functions.c:370:15: error: invalid type argument of unary '*' (have 'int')
functions.c:373:5: warning: passing argument 1 of 'strcmp' makes pointer from integer without a cast [enabled by default]
/usr/include/iso/string_iso.h:64:12: note: expected 'const char *' but argument is of type 'char'
What am I doing wrong? Please help me.
You declare airport as a char
char airport;
but use it as a string. Declare it char airport[100]; or so.
printf("Enter airport code: ");
scanf("%s", airport);
scanf requires a pointer to the variable the result shall be stored in as argument. When declared as char, airport is passed as an int to scanf, that is why the first message mentions int. The argument is dereferenced (unary *) to find the location where to store the scan result.
for(i=0;i<all_airports_size;i++){
if(strcmp(airport,all_airports_divid[i].code) == 0){
strcmp requires a pointer (to a 0-terminated string) as argument. If passed an integral type like char, without explicit cast, the compiler warns about that (because 99.99+% of the time it's wrong to do that).
Instead of passing a char to scanf, you need to pass it a char *; that is, a pointer to a place in memory where it can write the string that it finds.
To do this, instead of declaring airport as a single char, you need to declare it as an array; say, char[20]. This would not be suitable for a real application, because if the string was greater than 20 characters it would introduce a buffer overflow vulnerability, but it should be good enough for your purposes.
char airport;
Are you only expecting one char?
I think what you want is a char* hence that last line in the error.
Using char[42] would also work.
Or you could actually allocate some characters, but that doesn't seem to fit with this assignment.
char airport; // This must be a char* or char[] to hold the code
printf("Enter airport code: ");
scanf("%s", airport); // scanf expects address of the string, while airport is a char
for(i=0;i
Moreover, there is no field by the name of code in the declared struct
Related
This question already has answers here:
Char pointers and the printf function
(6 answers)
Closed 1 year ago.
For example, the following code returns an error and a warning when compiled and an int when changed to %d
Warning:
format %s expects argument of type char *, but argument 2 has type int
void stringd() {
char *s = "Hello";
printf("derefernced s is %s", *s);
}
*s is an expression of type char since it's the dereference operator applied to a pointer-to-char1. As a result, it gets promoted to an int when passed to printf; in order to print a null-terminated string, you need to pass the pointer to the first character (i.e. just s).
1 even though s is not a const pointer, you should not try to modify the characters it points to as they may be placed in read-only memory where string literals are stored on some architectures/environments; see this discussion for more details.
The variable s is a pointer to the first out of a series of characters which are consecutive in memory (colloquially referred to as a "string", though it's not quite the same). It's a pointer to a character, thus char *.
Dereferencing s (by doing *s) gives you the first of those characters, h, whose type is now just char. One layer of indirection was stripped away.
Thus, the issue is that you're trying to pass a character (char), where a string (char *) was expected. char * was expected because you used the %s type character in your format string to printf. Instead, you should use %c, which expects single, simple char.
The mistake here is actually quite grave. If you were allowed to pass this 'h' where a char * was expected, you would end up with the ASCII code of 'h' (0x68) being passed where a pointer was expected. printf would be none-the-wiser, and would try to dereference that value, treating 0x68 like a pointer to the beginning of a string. Of course, that's probably not a valid memory location in your program, so that should seg-fault pretty reliability, if it were allowed to happen.
This code compiles with a warning but prints the input string:
char staticArray[100];
scanf("%s",&staticArray);
printf("%s\n", staticArray);
Warning: format specifies type 'char *' but the argument has type 'char (*)[100]' [-Wformat]
This code also compiles with a warning but throws segmentation fault:
char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", &dynamicArray);
printf("%s\n", dynamicArray);
Warning: format specifies type 'char *' but the argument has type 'char **' [-Wformat]
I know both are wrong but, why does the first one prints the string value?
why does the first one prints the string value whereas second give segfault?
What's happening in Case I:
The type of staticArray is char [100] i.e. array of 100 char.
The type of &staticArray is char (*)[100].
The %s format specifier in scanf() expect the argument as a pointer to initial element of char array i.e. of type char *.
You are passing char (*)[100] type to scanf(), hence compiler is giving warning on this statement.
The &staticArray give you pointer to the array of type char (*)[100] which is numerically same as the base address of array.
Consider this example:
#include <stdio.h>
int main(void)
{
char staticArray[100];
printf ("staticArray: %p\n", (void*)staticArray);
printf ("&staticArray : %p\n", (void*)&staticArray);
return 0;
}
Output:
## ./a.out
staticArray: 0x7ffee4044a70
&staticArray : 0x7ffee4044a70
staticArray and &staticArray both yield a pointer to the same address1) but their type is different.
That's why when you pass &staticArray to scanf(), getting warning during compilation due to type mismatch but when scanf() called, it treat that pointer as char * and read input and store the result to given location. When printing it later, it prints the string value.
What's happening in Case II:
The type of dynamicArray is char *.
The type of &dynamicArray is char **.
So, you are passing char ** type to scanf() which expects char * when %s format specifier is used. Hence compiler is giving warning on this statement.
The pointer &dynamicArray is different from dynamicArray.
Consider this example:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char* dynamicArray;
dynamicArray = malloc(sizeof(char)*100);
if (dynamicArray == NULL) {
exit(EXIT_FAILURE);
}
printf ("dynamicArray: %p\n", (void*)dynamicArray);
printf ("&dynamicArray : %p\n", (void*)&dynamicArray);
free(dynamicArray);
return 0;
}
Output:
## ./a.out
dynamicArray: 0x7fd615401690
&dynamicArray : 0x7ffee7ab7ad0
dynamicArray and &dynamicArray both yield different pointer.
When you pass &dynamicArray to scanf() (which read input and store the result to given location), it lead to undefined behavior2) because your program end up accessing invalid memory.
When you pass &dynamicArray to printf() with format specifier %s, printf(), it access that address to write the character string and end up accessing invalid memory, lead to undefined behavior2). Hence, you are getting segfault.
1) An array is automatically converted to a pointer to its first element but there are few exceptions to this rule (C11 Standards#6.3.2.1p3):
The array is the operand of sizeof operator.
The array is the operand of _Alignof operator.
The array is the operand of &.
The array is a string literal used to initialize an array.
2) An undefined behavior includes it may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
Removing the & operator in both examples will solve the warnings. I'm not sure what your intended behavior is, but they seem to work correctly upon moving the & operator. This is because arrays are inherently pointers to the first element of the array so adding & is not what you want.
Working examples(exactly the same expect for &):
char staticArray[100];
scanf("%s",staticArray);
printf("%s\n", staticArray);
and
char* dynamicArray;
dynamicArray = (char*) malloc(sizeof(char)*100);
scanf("%s", dynamicArray);
printf("%s\n", dynamicArray);
I'm quite new to C and I'm having a bit of trouble with these pieces of code:
char word[STRING_LEN];
while(num_words < ARRAY_SIZE && 1 == fscanf(infile, "%79s", &word))
When I try to compile, I get the warning:
format '%s' expects argument of type char *, but argument 3 has type
char (*)[80].
Now this is remedied by using &word[0]. Now, shouldn't these both point to
the address at the start of the array? What am I missing here.
Cheers!
When you use %s format in fscanf, it is expected that the argument is a char* that can hold the characters being read from the stream. That explains the warning message.
In your case, &word has the same numerical value as &word[0]. However, that is not true all the time. For example, if you have:
char* word = malloc(20);
then, the numerical value&word is not equal to that of&word[0]. The compiler is not taking the responsibility for dealing with such distinctions. It is simply expecting a char* as the argument.
So I need to have a pointer to a value in a const char array. But I can't quite get it to work without errors. Here's the code.
int main (void)
{
const char *alp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char *ptr = &alp[3];
printf("%s\n", ptr);
return 0;
}
Edit- Sorry for not mentioning the errors. The thing is I get tons of different errors depending on where I put different asterisks and ampersands. There is no one particular error. One of the more frequent ones I get says
"incompatible integer to pointer conversion assigning to 'char *'
from 'const char';"
In the end I just want "ptr" to be equal to a pointer pointing to "D" in the array "alp".
If you only want one character to print, change the %s to %c and dereference the pointer
printf("%c\n", *ptr);
It's true that you had a character pointer but %s tells printf to print from that pointer until it reads a null character. So we switch to %c which will print one character but it expects a value rather than a pointer to a value.
alp is a pointer to constant char.
ptr is a pointer to a non-const char.
If you want that to work out you would need to change ptr to be defined as:
char const * ptr = &alp[3];
The const is saying that you're not going to change it, but then you're trying to copy the reference to a variable without that limitation. Instead, try:
const char *ptr = &alp[3];
But note that as other posters have already suggested, this code will give you a pointer to a string beginning with the D (e.g. DEFGHI...), not just the character D.
This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
confusion in scanf() with & operator
Why we need a & in scanf for inputting integer and why not for characters.
Do the & in scanf refers to merory location while getting input.
Eg:-
main()
{
int a;
char c;
scanf("%d",&a);
scanf("%c"c);
}
For each conversion specifier, scanf() expects the corresponding argument to be a pointer to the proper type: %d expects an argument of type int *, %f expects an argument of type double *, %c and %s both expect an argument of type char *, etc.
The difference between %c and %s is that the former tells scanf() to read a single character and store it in the location specified by the corresponding argument, while the latter tells scanf() to read multiple characters until it sees a 0-valued character and store all those characters in the buffer starting at the location specified by the argument.
You need to use the & operator on your arguments if they are not already of pointer type. For example:
int x;
int *px = some_valid_memory_location_such_as_&x;
char c;
char *pc = some_valid_memory_location_such_as_&c;
...
scanf("%d", &x); // x is not a pointer type, so we must use the & operator
scanf("%d", px); // px is a pointer type, so we don't need the & operator
scanf("%c", &c); // etc.
scanf("%c", pc); // etc.
Where things get confusing is reading strings of characters (using the %s conversion specifier):
char buf[SIZE];
scanf("%s", buf); // expression 'buf' *implicitly* converted to pointer type
Why don't we need the & operator in this case? It has to do with how C treats array expressions. When the compiler sees an expression of array type (such as buf in the scanf() call), it will implicitly convert the expression from type N-element array of T to pointer to T, and set its value to the address of the first element in the array. This value is not an lvalue -- it cannot be assigned to (so you can't write something like buf = foo). The only exceptions to this rule are when the array expression is an operand of either the sizeof or & operators, or if the array expression is a string literal being used to initialize another array:
char *p = "This is a test"; // string literal implicitly converted to char *,
// string *address* written to p
char a[] = "This is a test"; // string literal not implicitly converted,
// string *contents* copied to a
In short, the expression buf is implicitly converted from type char [SIZE] to char *, so we don't need to use the & operator, and in fact the type of the expression &buf would be pointer to SIZE-element array of char, or (*)[SIZE], which is not what scanf() expects for the %s conversion specifier.
The ampersand symbol is required in both cases. scanf requires pointers (you were probably thinking of char* or char[] - they are pointers themselves).
Scanf reads input to a memory address. a is the value held by a. &a is the location of a in memory.
In your code above, the c should be &c.
Because scanf() needs pointers, and &a is the pointer to an integer.
In your example, you need a comma and an ampersand in front of the c.
int main(void)
{
int a;
char c;
char s[21];
scanf("%d",&a);
scanf("%c", &c); // Fixed!
scanf("%20s", s);
printf("a = %d, c = %c, s = <<%s>>\n", a, c, s);
}
If you were reading a string, you would pass the string - a pointer to char - to scanf().
You need to provide scanf with pointer, that's why you have & in scanf("%d",&a);
. scanf("%c"c); will not work at all.
Your example is wrong. If you have a
char c;
then you need to add an & to the name when calling scanf:
scanf("%c", &c);
However, if your variable is already a pointer, for example because it is a char[] (which is a fancy syntax for pointers), you have to omit the &.
I like to think of the ampersand (&) as "address of". So you'd read &a as "address of a".
Also, I tried compiling this but it warned me on gcc:
Warning: format "%c" expects type 'char *', but argument 2 has type 'int'
Which is true, since a char is basically an int.