Is printf unsafe to use in C - c

I am new to C so I started playing around with some code. I have a bug in my code as I believe using printf(pass) is not safe to use because it can overwrite the value and hence not safe for the user. I was wondering am I right about it that printf(pass) is not safe in my code? Also, how can I still let user print the message finally logged in without changing my code. Is there any way to do that?
My code:
#include <stdio.h>
char pass[100];
char getPass() {
int value = 'G';
int * j = & value;
fgets(pass, sizeof(pass), stdin);
printf("your entered pass is ");
printf(pass);
return (char)( * j);
}
void main() {
printf("enter the pass here ");
if (getPass() == 'K') {
printf("finally logged in\n");
exit(0);
} else {
printf("Wrong password\n");
exit(1);
}
}

Yes it's unsafe, but not for the reason you suggested. If you check the man page for the printf() function, you'll see it has the following prototype:
int printf(const char * restrict format, ...);
The const modifier applied to the first argument specifies that the value of this parameter will not be changed when you call this function.
However, you'll also notice that this parameter is called format. That's because it's supposed to specify a format string. In your program, there's nothing to stop a user entering a format specifier like %p, in which case your call to printf() will start printing out the contents of the stack. There's a Wikipedia article that describes this vulnerability in more detail.

The function fgets if its call was successful provides a string that you can output.
A problem can arise if the obtained string is outputted such a way
printf(pass);
and contains conversion specifiers.
So instead of that call
printf(pass);
it is a more safer to use
printf( "%s", pass );
or
puts(pass);
Preliminary you can remove the new line character stored in the string by the call of fgets.

Related

How do I write a short C program that accepts words and prints them?

I wrote the below code but I keep getting a "Command terminated by signal 11".
#include<stdio.h>
int main()
{
char *goodnight_message[20];
printf ("Enter the goodnight message.\n");
scanf ("%s", &goodnight_message);
printf ("%s Buddy.\n", *goodnight_message);
return 0;
}
I suspect that you want one char array with 20 chars, not an array of 20 char* which is what you've got now.
Note that when passing arrays to functions, like scanf and printf, they decay into pointers to the first element. Also note that when using scanf to read strings, always set a maximum number of characters to read (one less than the size of the array to leave room for the null terminator). Otherwise the user may enter more characters and your program will write out of bounds.
You should also always check if scanf is successful by checking if it returns the same number of conversions you requested. You request one only, so check if it returns 1.
A working program would then look like this:
#include <stdio.h>
int main() {
char goodnight_message[20]; // now a char[] instead
printf("Enter the goodnight message.\n");
if(scanf("%19s", goodnight_message) == 1) { // decays into a char*
printf("%s Buddy.\n", goodnight_message); // decays into a char*
}
}
This will however not read more than one word. To make scanf read until a newline you can add a set of characters to match in the conversion specifier with [characters].
If the first character of the set is ^, then all characters not in the set are matched.
We want all characters except \n so lets add the set [^\n]
#include <stdio.h>
int main() {
char goodnight_message[20];
// an alternative to printf when you don't need formatting is puts:
puts("Enter the goodnight message.");
if(scanf("%19[^\n]", goodnight_message) == 1) {
printf("%s Buddy.\n", goodnight_message);
}
}
There seems like you have a misconception of array and pointers..
While using array-like goodnight_message[20];
The correct way to address its address is to use &goodnight_message[0] indicating the beginning of the array or to use goodnight_message simply. Both of these point to the 0th index of the array..
#include<stdio.h>
int main()
{
char *goodnight_message[20];
printf ("Enter the goodnight message.\n");
scanf ("%s", goodnight_message);
printf ("%s Buddy.\n", goodnight_message);
return 0;
}
Tip: You should use gets(goodnight_message) instead of scanf when you want a string that includes a space. You can also do this by using scanf("%[^\n]s",goodnight_message);, like this:
#include<stdio.h>
int main()
{
char *goodnight_message[20];
printf ("Enter the goodnight message.\n");
scanf ("%[^\n]s", goodnight_message);
printf ("%s Buddy.\n", goodnight_message);
return 0;
}
line char *goodnight_message[20]; creates an array of strings (array of char pointers)
to create single string use char *goodnight_message; or char goodnight_message[20];
warning: if you use char *goodnight_message;, you have to malloc it, so just stick to [20] for now
scanf ("%s" reads one string from input, but note that it is only to the next whitespace
for example, input good night would read only good and output good buddy
to read whole line use gets(goodnight_message) or getline
warning: getline is a bit complicated (explanation)

Why variables set in a function are lost?

I am trying to pass the parameters in c through a function. The version with a string argument is working fine but both versions with integer arguments are returning 1 as a result.
#include<stdio.h>
void main()
{
char s1[10];
int a,b;
clrscr();
printf("name=%s\n",getname(s1));
printf("mobile=%d\n",getmobile(a));
printf("mobile=%d\n",getrno(b));
getch();
}
getname(char s[10])
{
printf("enter the name\n");
gets(s);
return ;
}
getmobile(int a)
{
printf("enter the mobile number\n");
scanf("%d",&a);
}
getrno(int b)
{
printf("enter the rno\n");
scanf("%d",&b);
}
The reason why your getname works is but getrno doesn't is because of pass-by-reference vs. pass-by-value semantics and because arrays, like s1 decay to pointers. These are important concepts to understand if you want to program in C.
Think of it like this: When you call getname it accepts a local copy of the address of a buffer. The function then writes into the buffer itself. But when you call your getrno the function accepts a local copy of an integer and reads the value into that local copy, so that nothing changes in the program outside.
#askmish has proposed a good solution, but I would strongly advise something like this instead:
// getrno will prompt the user to enter the rno and will store it into the variable
// pointed to by b. If the function returns 1 then a value was successfully read.
int getrno(int* b)
{
// make sure that the pointer looks valid
if (b == NULL)
return 1;
// prompt the user to enter the text
puts ("enter the rno: ");
// Note the use of a single space at the beginning of the format string
// which is used to consume any whitespace (including return characters
// that might be present)
if (scanf (" %d", b) == 1)
return 0;
// We couldn't read one integer. Return an error.
return 1;
}
int main()
{
int x;
if (!getrno (&x))
printf ("rno = %d\n", x);
else
printf ("failed to get rno!");
return 0;
}
You ask how to go about doing floating-point numbers. The solution is to write a function which accepts, as necessary, either a float or a double pointer and which then calls scanf with the correct format specifier, to read the value into that pointer. This function would look very much like the getrno I showed you above.
Functions should be written like this, for example:
int getrno(int b)
{
printf("enter the rno\n");
scanf("%d",&b);
return b;
}
to get a return value aka, it must have a return-type and a return statement returning value of the specified return-type. Your code had both missing.
I would also suggest to read a good book in C or atleast this page in wikibooks, to understand better and writing better code.

String input using C scanf_s

I've been trying to look for answer myself, but I can't find one.
I want to insert a part of the programming that reads in a string like "Hello" and stores and can display it when I want, so that printf("%s", blah); produces Hello.
Here's the code part that's giving me trouble
char name[64];
scanf_s("%s", name);
printf("Your name is %s", name);
I know that printf isn't the problem; the program crashes after something is input after a prompt. Please help?
From the specification of fscanf_s() in Annex K.3.5.3.2 of the ISO/IEC 9899:2011 standard:
The fscanf_s function is equivalent to fscanf except that the c, s, and [ conversion
specifiers apply to a pair of arguments (unless assignment suppression is indicated by a
*). The first of these arguments is the same as for fscanf. That argument is
immediately followed in the argument list by the second argument, which has type
rsize_t and gives the number of elements in the array pointed to by the first argument
of the pair. If the first argument points to a scalar object, it is considered to be an array of
one element.
and:
The scanf_s function is equivalent to fscanf_s with the argument stdin
interposed before the arguments to scanf_s.
MSDN says similar things (scanf_s() and fscanf_s()).
Your code doesn't provide the length argument, so some other number is used. It isn't determinate what value it finds, so you get eccentric behaviour from the code. You need something more like this, where the newline helps ensure that the output is actually seen.
char name[64];
if (scanf_s("%s", name, sizeof(name)) == 1)
printf("Your name is %s\n", name);
I used this very often in my university classes so this should work fine in Visual Studio (tested in VS2013):
char name[64]; // the null-terminated string to be read
scanf_s("%63s", name, 64);
// 63 = the max number of symbols EXCLUDING '\0'
// 64 = the size of the string; you can also use _countof(name) instead of that number
// calling scanf_s() that way will read up to 63 symbols (even if you write more) from the console and it will automatically set name[63] = '\0'
// if the number of the actually read symbols is < 63 then '\0' will be stored in the next free position in the string
// Please note that unlike gets(), scanf() stops reading when it reaches ' ' (interval, spacebar key) not just newline terminator (the enter key)
// Also consider calling "fflush(stdin);" before the (eventual) next scanf()
Ref: https://msdn.microsoft.com/en-us/library/w40768et.aspx
The scanf_s function is equivalent to scanf except that %c, %s, and %[ conversion specifiers each expect two arguments (the usual pointer and a value of type rsize_t indicating the size of the receiving array, which may be 1 when reading with a %c into a single char)
Your code doesn't provide the size of receiving array, also the variable name is a pointer pointing to the first character of the array, so it contains the address of name[0]. Therefore your first argument name in scanf_s is correct because name is a pointer, also note that, for the second argument you can't insert the size of a pointer like sizeof(name) because it is always same. You need to specify the size of your char array (name[64]), so for the second argument you should insert sizeof(name[64]) or 64*sizeof(char).
You can correct your code as follows:
char name[64];
if (scanf_s("%s", name, sizeof(name[64])) == 1)
printf("Your name is %s\n", name);
Here is a part of code that works for me fine:
char name[64];
scanf_s("%63s", name,(unsigned)_countof(name));
printf("Your name is %s", name);
For more information here is a link:
https://learn.microsoft.com/de-de/cpp/c-runtime-library/reference/scanf-s-scanf-s-l-wscanf-s-wscanf-s-l?view=msvc-170
Best Regards
#include<stdio.h>
int main()
{
char name[64];
printf("Enter your name: ");
scanf("%s", name);
printf("Your name is %s\n", name);
return 0;
}
#include<stdio.h>
int main()
{
char name[64];
printf("Enter your name: ");
gets(name);
printf("Your name is %s\n", name);
return 0;
}
you should do this : scanf ("%63s", name);
Update:
The below code worked for me:
#include <stdio.h>
int main(void) {
char name[64];
scanf ("%63s", name);
printf("Your name is %s", name);
return 0;
}
if you are using visual studio,
go to Project properties -> Configuration Properties -> C/C++-> Preprocessor -> Preprocessor Definitions click on edit and add _CRT_SECURE_NO_WARNINGS click ok, apply the settings and run again.
Note: this is only good if you are doing your homework or something like that and it's not recommended for production.

Using the scanf() function

I intend to modify each other letter of a particular string. But for the purposes of this program none of that occurs. So far I've grabbed a string from the user and stored it in userinput and intend to print it.
#include <stdio.h>
#include <string.h>
int main(void) {
char userinput[256] ="";
printf("Enter somthing to change:\n");
scanf("%s", &userinput);
printf("%s\n", userinput);
int k = 2; // This is just here to do something every time k is even
int j = strlen(userinput);
for (int i = 0; i < j; i++) {
if(k % 2 == 0) {
printf("%s", userinput[i]);
k++;
}
else {
printf("%s", userinput[i]);
k++;
}
}
}
The strlen() function however does not work on the userinput. I figure this is because strlen() is supposed to take the address of the first char of a string and then iterate until reaching a null char but scanf doesn't actually create a null char.
I couldn't figure out a way of adding the '\0' after the string without first knowing the length of the string.
How would I go about accessing the length of a stored character sequence if it's stored in an array?
This:
scanf("%s", &userinput);
should be:
scanf("%s", userinput);
The address of operator & is unrequired, and incorrect. Arrays decay to the address of their first element when passed to a function. scanf("%s") will append a null terminating character so it is unnecessary to explicitly insert one.
To prevent potential buffer overrun specify the maximum number of characters that scanf() should write to userinput. This should be one less than the size of userinput, leaving room for the terminating null character:
scanf("%255s", userinput);
The incorrect format specifier (which is undefined behaviour) is being used to print the characters of userinput: use %c not %s. This:
printf("%s", userinput[i]);
must be:
printf("%c", userinput[i]);
Change
scanf("%s", &userinput);
to
scanf("%s", userinput);
The & operator is not required in the case of String capture. The scanf() automatically appends the null character('\0') to the end of the string so int j = strlen(userinput); should work.
If you still want to calculate the length without this function efficiently here is the link How to calculate the length of a string in C efficiently?
Change this
scanf("%s", &userinput);
with
scanf("%s", userinput);
we have to use addresses for scanf:
If we will scan into an int a then we have to call scanf() with the address of a => &a
If we will scan into a double a then we have to call scanf() with the address of a => &a
But If we will scan data into with pointer (memory address) int *a; or char array char a[50]; then we have to call scanf() with the pointer or with the array without adding &
From the scanf() page
Depending on the format string, the function may expect a sequence of
additional arguments, each containing a pointer to allocated storage
where the interpretation of the extracted characters is stored with
the appropriate type. There should be at least as many of these
arguments as the number of values stored by the format specifiers.
Additional arguments are ignored by the function. These arguments are
expected to be pointers: to store the result of a scanf operation on a
regular variable, its name should be preceded by the reference
operator (&) (see example).
You're confused about types, as others have indicated. Using scanf and printf when you're confused about types is dangerous!
scanf("%s", &userinput);
The type of &userinput is char (*)[256], but scanf expects %s to correspond to a char *. Since the type expected and the type given differ and aren't required to have the same representation, the behaviour is undefined.
I figure this is because strlen is supposed to take the address of the
first char of a string and then iterate until reaching a null char but
scanf doesn't actually create a null char.
Wrong. scanf certainly does assign a null character, when you use the %s format specifier. That is, providing scanf doesn't encounter an error or EOF. On that note, you should probably check for errors from scanf:
if (scanf("%s", userinput) != 1) {
/* Insert error handling here */
}
... as you should with all standard library functions in C.
k is pointless. Your loop already increments i at the same frequency as k.
strlen returns a size_t. Make sure you store return values in the right types. If a function returns size_t, then you store the return value in size_t. If a function returns int, then you store the return value in an int. Got it? Whatever the return type is, is whatever type you use to store the return type. Use the manual to find that out.
printf("%s", userinput[i]);
There's that type confusion again. userinput[i] is a char. %s tells printf to expect a char *. When the argument is invalid, the behaviour is undefined. That may cause your program to malfunction. Consider printf("%c", userinput[i]); or printf("%s", &userinput[i]);.

While loop to retrieve input, not working correct in C

I have a problem when using a user input method which allow validates the input.
I require to return the input after its been validated.
char* getvalidinputnumber(int length, char prompt[],int base)
{
char* user_input = calloc(length+1,sizeof(char));
fflush(stdin);
fflush(FILE *);
/*Prompts & Gets the users input and saves it in user_input*/
do {
printf("\n %s", prompt);
fgets(user_input,length+1,stdin);
/*printf("\n##Entered %s : ", user_input);*/
} while(!isnumeric(user_input,base) && strlen(user_input) != length);
fflush(stdin);
return(user_input);
}
When calling this function within my main like....
while (strcmp(user_input,"00000000") != 0)
{
user_input = getvalidinputnumber(8, "Enter HEX Value",16);
}
It also does the following ...
Enter HEX Value
Enter HEX Value
Twice rather than just once and when i enter a hex value it returns the hex correct but then runs twice again ive tryed using fflush but this doesnt seem to solve it.
How could i solve this or is there a better way to get the input for example using scanf?
fflush(stdin)
Causes an Undefined Behavior! fflush() should only be used on streams open for output, not input.

Resources