C fscanf formatting - c

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.

Related

Why we didn't use * during dereferencing the pointer?

In the below code, we get a pointer from strdup(source) and we store it in a pointer named target.
Now, when we print the string using pointer, we don't add * at the beginning of the pointer: why is it so? As I studied whenever we want to dereference any pointer we use *pointer_name. If we add * in the below code, we get an error.
I am very beginner, so pls ans in easy words.
#include<stdio.h>
#include<string.h>
int main()
{
char source[] = "Programming";
char* target = strdup(source);
printf("%s\n",target);
return 0;
}
printf expects a char pointer in the place of the %s specifier.
https://en.cppreference.com/w/c/io/fprintf
char* target = strdup(source);
printf("%s\n",target);
Why we don't use *target in the code above?
The explanation is quite simple, as already stated in previous answers: target has type char pointer, which is exactly what printf() wants in the above call.
Now, printf() is a little complicated because its semantic is not simple - basically it accepts zero or more arguments after the first, of any type (possibly applying promotion). But if we use strdup() again, maybe it is simpler:
char* target2 = strdup(target);
Here, if you wrote strdup(*target), the compiler might warn that you are passing a char instead of a pointer to char.
strdup() returns a char*, hence the char* type of target. target holds a pointer to the first character in an array of chars. printf("%s", string) expects string to be a char*, so there’s no reason to do anything to target; just pass it to printf().
If you dereferenced target, you would get a single char (P in this case). printf() would then complain that you had supplied a character instead of a string (pointer to character). Even worse, the program could compile, and then printf() would try to print the string at address P (0x50), which would result in probably unwanted behaviour.
When working with arrays—a string is a type of array—you rarely want to dereference the array.

C: Returning D as output why?

#include <stdio.h>
int main(){
char *s="hello world";
printf("%c\n",s);
}
I have written a small code in C. In last statement of this code I'm using %c format-specifier in printf() function and assigning pointer named s in it. It is giving me D as output. Does it is returning garbage value or does my code automatically assigning ASCII value in it or something else?
When I add s+1 it return E and s+2 return F and so on. Can anyone clarify me?
%c prints a char, not a string. Since your variable s is not a char, but rather a pointer to a char, printf interprets the address to your string as a character. You probably want to use one of the snippets:
printf("%c\n", s[0]); // print the first character in your string
printf("%s\n", s); // print the whole string
regarding:
printf("%c\n",s);
results in the compiler output:
*untitled2.c:5:14: warning: format ‘%c’ expects argument of type ‘int’, but argument 2 has type ‘char *’ *[-Wformat=]*
When compiling, always enable the warnings, then fix those warnings. Suggest:
printf("%s\n",s);
so the statement is using the correct 'output format conversion' specifier to output the whole string
--OR--
to output a single character suggest:
printf( "%c\n", s[0] );
to output only the first character h
On considering how you are doing in this code lets just say, yes you are getting garbage values when you are giving s/s+1/s+2... in printf(). That's just because of your format specifier%c(type is char) is being mismatched with s( type is string). The fix is change the latter to type char and your problems will be fixed.
You don't need to worry about where this value is coming from as, at the end of the day it's a garbage value and will be different for different for different people using the code. And there is no possible usage for it as far as I can see.
Try the following code below and your code will work fine:
char *s="hello world";
printf("%c\n",*s);
or
char *s="hello world";
printf("%c\n",s[0]);
These answers are discussed in answers and comments above.But you should also try this,
char s[]="hello world";
printf("%c\n",s[0]);
Because, although pointers are present in C, swift,etc. They are discouraged because they present major issues for memory safety and garbage collection.
Edit: Stackoverflow fam need some upvotes at the current state i can't even comment. (Only if
i am right)

add string to given command line argument in C

Hello i just started to programm in C and i am trying to read a file and give the file name as argument without the ending .txt . I want to add .txt in my code : ./myexample.exe file
if i use file.txt there is no problem but i dont know how to change argv[1]
i tried char *n = argv[1] + ".txt"; it doesnt works and i dont know anything else..
int main(int argc, char* argv[]) {
char *n = argv[1] +".txt";
FILE *fp1;
fp1 = fopen(n , "r");
Thats what i get if i use char *n = argv[1]+".txt"
error: invalid operands to binary + (have 'char *' and 'char *')
In your code,
char *n = argv[1] +".txt";
does not do what you think it does. In C, the + cannot be used to concatenate strings.
FYI, from C11, chapter §6.5.6
For addition, either both operands shall have arithmetic type, or one operand shall be a
pointer to a complete object type and the other shall have integer type. (Incrementing is
equivalent to adding 1.)
Both the operands cannot be of pointer-to-object type.
If you meant to concatenate strings, use strcat() but make sure
the destination is modifiable (attempt to modify string literal is UB)
the destination got enough space to contain the final result (shorter destination lead to access out of bound memory invoking UB, again).
You can't concatenate strings with +. Use strcpy and strcat:
char n[256];
strcpy(n, argv[1]);
strcat(n, ".txt");
Make sure that n is large enough to hold the filename + extension.
This is kind of annoying to do safely: you need to be careful to make a big enough char array to hold the whole string. One way:
size_t arglen=strlen(argv[1]);
char* filename=malloc(arglen+5); //Enough to hold the whole string
strcpy(filename,argv[1]);
strcat(filename,".txt");
Be sure to free the pointer later.

C: why printing a null char with %s prints "(null)"?

Why does printing a null char ('\0', 0) with %s prints the "(null)" string actually?
Like this code:
char null_byte = '\0';
printf("null_byte: %s\n", null_byte);
...printing:
null_byte: (null)
...and it even runs without errors under Valgrind, all I get is the compiler warning warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat] (note: I'm using gcc 4.6.3 on 32bit Ubuntu)
It's undefined behavior, but it happens that on your implementation:
the int value of 0 that you pass is read by %s as a null pointer
the handling of %s by printf has special-case code to identify a null pointer and print (null).
Neither of those is required by the standard. The part that is required[*], is that a char used in varargs is passed as an int.
[*] Well, it's required given that on your implementation all values of char can be represented as int. If you were on some funny implementation where char is unsigned and the same width as int, it would be passed as unsigned int. I think that funny implementation would conform to the standard.
Well, for starters, you're doing it wrong. '\0' is a character and should be printed with %c and not %s. I don't know if this is intentional for experimentation purposes.
The actual binary value of \0 is, well, 0. You're trying to cast the value 0 to a char * pointer, which would result in an invalid reference and crash. Your compiler is preventing that with a special treatment of the %s value.
Valgrind won't catch it because it runs on the resulting binary, not the source code (you'd need a static analyzer instead). Since the compiler has already converted that call into a safe "null pointer" text, valgrind won't see anything amiss.
null_byte contains 0. When you use %s in printf, you are trying to print a string, which is an adress of a char (a char *). What you do in your code, is that you are passing the adress 0 (NULL) as the adress of your string, which is why the output is null.
The compiler warned you that you passed the wrong type to the %s modifier. try printf("null_byte: %s\n", &null_byte);
Your printf statement is trying to print a string and is therefore interprets the value null_bye as a char * that has the value null. Take heed of the warning. Either do this
printf("null_byte: %s\n", &null_byte);
or this
printf("null_byte: %c\n", null_byte);
Because printf is variadic, the usual argument promotions are performed on null_byte so it gets promoted (cast) to int, value 0.
printf then reads a char * pointer, and the 0 int is interpreted as a null pointer. Your C standard library has a feature that null strings are printed as (null).
Adding an implementation example to other answers, in XV6, which is an educational re-implementation of Unix v6, if you pass a zero value to %s, it prints (null):
void printf(int fd, const char *fmt, ...) {
uint *ap = (uint*)(void*)&fmt + 1;
...
if(state == '%') {
...
if(c == 's') {
s = (char*)*ap;
ap++;
if(s == 0)
s = "(null)";
while(*s != 0){
putc(fd, *s);
s++;
}
}
}
}

Confused about pointers and structures

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

Resources