scanf and char pointers in C -- unexpected output [closed] - c

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
void main(int argc, char * argv[])
{
FILE* inFile = NULL;
char * bufferFromStdin;
char buf[100];
printf("Enter something:\n");
scanf("%s", buf);
printf("First scan from stdin is: %s\n", buf);
if(buf == "THIS" || buf[0]=='T')
{
printf("THIS found first\n");
}
else {printf("Not Found first\n");}
printf("Enter something again:\n");
scanf("%s", bufferFromStdin);
printf("Second scan from stdin is: %s\n", bufferFromStdin);
if(bufferFromStdin == "THIS")
{
printf("THIS found second\n");
}
else {printf("Not Found second\n");}
}//main
gives me the output:
./test < testinput.txt
Enter something:
First scan from stdin is: THIS
THIS found first
Enter something again:
Second scan from stdin is: (null)
Not Found second
testinput.txt has one line of text "THIS"
this is what I get when I run the program with input as regular stdin
./test
Enter something:
THIS
First scan from stdin is: THIS
THIS found first
Enter something again:
THIS
Second scan from stdin is: (null)
Not Found second
How come the input cannot be saved to a char* when using either input method and how would I work around this? I need to get input from stdin by the keyboard and redirecting I/O as well. I think it's something to do with malloc();
Thanks for the help.

You have two critical errors in your code. First of all, bufferFromStdin does not point to allocated memory. scanf requires a pointer to memory that has been previously allocated (such as buf in your example) where it will store the result. When you pass an uninitialized variable such as bufferFromStdin the result is undefined.
Second, the == operator in C compares two pointers, not what they are pointing to. Therefore, buf == "THIS" will never be true, since buf isn't pointing to a constant array. In order to compare two strings, use strcmp. Of course, both pointers need to point to something for this to work.
Also, as a side note, main should always return int not void.
Once you correct those two problems, your code should work:
int main(int argc, char * argv[])
{
char buf[100];
printf("Enter something:\n");
scanf("%s", buf);
printf("First scan from stdin is: %s\n", buf);
if(strcmp(buf, "THIS") == 0) {
printf("THIS found first\n");
} else {printf("Not Found first\n");}
return 0;
}

you have a couple of programming errors in your code.
void main(int argc, char * argv[])
{
FILE* inFile = NULL;
char * bufferFromStdin;
char buf[100];
you are allocating three pointer variables, using three different styles:
inFile is properly initialized (NULL pointer).
bufferFromStdin is not initialized.
buf is initialized and points to a statically allocated area.
you probably want to check how one allocates memory in C.
printf("Enter something:\n");
scanf("%s", buf);
this scanf call is just a bit dangerous. if the user inserts a string that is longer than 99 chars (remember the \0 terminator), it will overflow the buffer. you probably want to check this question.
printf("First scan from stdin is: %s\n", buf);
if(buf == "THIS" || buf[0]=='T')
I'm sorry to say, but I find this quite funny! you want to test string equality (content, not pointer) and you see the first test does not work (you are comparing pointers) so you add a second test. check the manual pages.
{
printf("THIS found first\n");
}
else {printf("Not Found first\n");}
I find this also a bit ugly. you might want to stick to one style for indenting.
printf("Enter something again:\n");
scanf("%s", bufferFromStdin);
you are using your uninitialized pointer. what happens here depends on your programming environment, operating system, compiler. a strong operating system will probably terminate your program. or you are corrupting some memory areas.
printf("Second scan from stdin is: %s\n", bufferFromStdin);
if(bufferFromStdin == "THIS")
same problem as above, but you forgot to implement your workaround.
{
printf("THIS found second\n");
}
else {printf("Not Found second\n");}
}//main

Related

Visual Studio Code and C programming

I'm attempting to learn C and decided to use Visual Studio as a base for where I can practice my code. I have everything set up already and have started writing up code as well but I seem to be running into a problem where I cannot see the user input.
Here is my program:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char string[] = "";
char reversed[] = "Placeholder";
printf("Please enter an input string.\n");
scanf("%s", &string);
printf("Your original string is %s\n", string);
printf("The string reversed is %s", reversed);
return 0;
}
When I run this program, the first printf statement is never printed nor is the user input ever shown
anywhere (not in the terminal either). All it says is that the program is running. When I force stop it,
it will say 'Done!' and that's all that ever happens (I have to force stop because I never see the place to input the string therefore the program just keeps running waiting for an input). I just set up Visual Studio so it is possible I missed something and this is an easy fix but not quite sure what it is.
The string you're inputting is empty. First avoid naming variables "string" as in standard libraries there might already be defined one. And try to allocate more space for your string to be able to input data.
`
char str[128];
char reversed[] = "Placeholder";
printf("Please enter an input string.\n");
scanf("%s", &str);
printf("Your original string is %s\n", str);
printf("The string reversed is %s", reversed);
return 0;
`
Also, be sure to read more about arrays, strings and functions in c. The code you've written is probably not gonna work as you've intended.
There are a couple of problems.
You're not allocating any memory for string, so when the user inputs something, its written into memory it doesn't own, resulting in undefined behavior.
Your scanf is wrong,, kind of. You must provide it a pointer to the memory where the input should go, you're providing the address of the pointer. In this case, they're one in the same, but if that was a pointer to heap memory, for instance, &string would not point to the memory you've reserved.
Instead, try something like this:
int main()
{
char string[64] = ""; // string can now hold 63 user-input characters plus
// one for the NUL terminator, which scanf will add
// automatically.
char reversed[] = "Placeholder"; // This reserves at least 12 bytes, 11 for the text plus the NUL terminator.
printf("Please enter an input string.\n");
scanf("%s", string); // string decays to a pointer to where its memory is allocated.
printf("Your original string is %s\n", string);
return 0;
}
Note, you can still overflow your string buffer if you enter (in this case) more >= 64 characters, and you'll be back where you started. I believe there is a way for scanf to limit the amount of input accepted, but will need to look up how. Another option is to use fgets to accept limited input.

Why does my program pause after using scanf? [duplicate]

This question already has answers here:
How to read from input until newline is found using scanf()?
(7 answers)
What is the effect of trailing white space in a scanf() format string?
(4 answers)
Closed 6 years ago.
#include<stdio.h>
#include<stdlib.h>
int main()
{
char *userInput;
userInput = (char*)malloc(sizeof(userInput));
printf("Commands:\n");
printf("\ta name - adds given name to list\n");
printf("\tr name - removes given name from list\n");
printf("\tp - prints out list\n");
printf("\te - exits\n");
printf("\n\nEnter a command: ");
scanf("%s\n",userInput);
printf("\nThe user input was: %s\n", userInput);
return 0;
}
I compile the code "gcc -std=gnu99 -m32 -Wall -g -o namelist namelist.c"
whenever I run the executable all of the first printf are displayed and I get prompt on an input. Whenever I enter an input and press enter, I don't get prompt the next printf until I put another input in.
While a character (char) or set of characters (char*) are coming from stdin with scanf of similar function \n (result of Enter key pushing) remains in the buffer. So before next input the program should clean that \n as well as all other mess that can be in the input buffer (e.g. after incorrect entering numbers, such as 12asw - scanf takes 12 and leaves asw\n in the buffer).
Consider the following example and pay attention, that I recommend to use clnInpBuf():
#include <stdio.h>
void clnInpBuf()
{
char c;
while ((c = getchar()) != '\n' && c != EOF);
}
int main(void)
{
char str[10];
char ch;
scanf("%c", &ch);
fflush(stdin); // in some cases that works for input stream
// (but fflush is better to use only for output streams)
scanf("%9s", str);
clnInpBuf(); // this works always
printf("char was %c.\n", ch);
printf("string was %s.\n", str);
}
UPDATE:
template for your "command processor" can be:
int main(void)
{
char name[21];
char command;
while (1)
{
scanf("%c", &command);
clnInpBuf();
switch (command)
{
case 'a':
case 'r': scanf("%20s", name);
clnInpBuf();
printf("Command was:\n%c %s\n", command, name); // if ('a'==command) addRecord(name); else removeRecord(name);
break;
case 'p': // TODO: add output
break;
case 'e': return 0;
break; // this is not realy needed
default:
printf("Wrong command\n");
}
}
}
Just take out the "\n" in your
scanf("%s\n",userInput)
Read carefully scanf(3). Notice that with gcc -m32 you have sizeof(userInput) equal to 4 (the size of all pointers is the same; without the -m32 it would be 8). So if the user is typing something like working (or any input of four characters or more, not just one letter like a), you have undefined behavior (because of a buffer overflow) and that is really bad. You probably should consider using getline(3) instead (or perhaps even readline(3)), e.g.
char* userInput=NULL;
size_t sizeInput= 0;
printf("Commands:\n");
/// put your other printfs here, then
ssize_t lengthInput = getline(&userInput, &sizeInput, stdin);
if (lengthInput < 0 || userInput==NULL)
{ perror("input error"); exit(EXIT_NULL); };
Now you have the entire typed line in userInput (including the terminating newline) and you know that its length is lengthInput. You can parse that line, perhaps using sscanf(3) (hint: use its return count, and consider using %n) or just using other techniques (some strcmp, or strtok(3)...). When done, you should free(userInput).
Notice that scanf (or sscanf) do not allocate any memory for parsed data, unless you use %ms (which is probably POSIX specific). With %s it always expecting some fixed length buffer, and for a array buffer declared char buf[64]; you'll better give the size with %63s; BTW, you should always test the result count of scanf. So you might code (after the above)
char nambuf[64];
if (sscanf(userInput, "a %63s", nambuf)==1) {
// use nambuf to add it
}
else if (sscanf(userInput, "r %63s", nambuf)==1) {
// use nambuf to remove it
}
(but the above is a bit silly, we read an arbitrary sized line but process nambuf of at most 63 bytes). You could just use scanf like if (scanf("a %63s", nambuf)==1) without needing any userInput.
Alternatively, you could use the Linux specific %as or better the POSIX specific %ms like:
char* nameptr=NULL;
if (scanf("a %ms", &nameptr)==1) {
then that successful scanf would have malloc-ed and filled nameptr and you should later free(nameptr). If you want to accept only lowercase letters consider coding something like if (scanf("a %m[a-z]", &nameptr)==1) etc...
This statement will allocte 4 bytes of data as userinput is pointer.
userInput = (char*)malloc(sizeof(userInput));
as pointed by the above answer this will cause a buffer overflow when the string size is more than 3 bytes.
also i would suggest fgets() over scanf when reading a string
sample code -
#include <stdio.h>
#include <stdlib.h>
int main() {
// your code goes here
char *userinput = (char *)malloc(100);
fgets(userinput,100,stdin);
printf("%s",userinput);
return 0;
}

What is causing my print statements to produce different results? [duplicate]

This question already has answers here:
Crash or "segmentation fault" when data is copied/scanned/read to an uninitialized pointer
(5 answers)
Closed 6 years ago.
I'm a newbie learning to program in C, and I am currently working on creating a program that takes a name input from a user then prints that name back on to the screen. When the program prints out the name in the else if block, what I get is $ ". I want to know why it happens and how I might correct this problem. My code is as follows:
#include <stdio.h>
#include <stdlib.h>
int main() {
char * ans; // yes/no answer
char * name; //name variable
printf("Welcome to the program. Would you like to begin? (y/n)\n");
scanf("%s", ans);
if (strcmp(ans, "y") != 0) {
printf("Have a good day!\n");
return 0;
}
else if (strcmp(ans, "y") == 0)
printf(" %s\n", ans);
printf("Okay, input your name:\n");
scanf("%s", name);
printf(" %s", name);// I get $ " rather than the name.
return 0;
}
You are using scanf() to read characters from the user, but haven't allocated any memory to hold those characters. This gives undefined behavior, as "anything can happen" when you break the rules like that.
Make those uninitialized pointers into arrays instead:
char ans[128];
char name[128];
This gives you 128 characters of space for each string (one of which will be used by the terminator).

C - If else scanf not working as expected

I'm new to coding in general, and very new to C.
I'm trying to write a program in c that asks the user for input and based on that users input, prints specific text to a .txt file. Please have a look at my code and let me know what I'm doing wrong.
Please have a look at my code below. Thanks very much for your assistance.
Matt
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
FILE * fptr;
int main(){
char name[32];
char partNum[32];
char desc[250];
char ans1;
char ans2;
char sn[50];
char ansRep;
fptr = fopen("C:\\Users\\mgreene\\Documents\\EmailTemplates\\QCIssue.txt", "w");
if (fptr ==0)
{
printf("Error--file could not be opened\n");
exit(1);
}
printf("What is the customer's first name?\n");
scanf("%s", name);
printf("With which Part number is the user experiencing difficulties?\n");
printf("Enter Part Number:");
scanf("%s", partNum);
printf("Please enter a brief description of the problem\n");
scanf("\n%s", desc);
printf("Does the product have a serial number?\n");
scanf("%c", &ans1);
if (!strcmp(&ans1, "y")== 0)
{
printf ("Do you know the serial number?\n");
scanf("\n%c", &ans2);
if (!strcmp(&ans2, "y")==0)
{
printf ("Please enter the SN:\n");
scanf("\n%s", sn);
fprintf(fptr, "\nHi %s,\n\nI hope this message finds you well.\n\nI write to you today as the Quality Manager at Blank. I received a report that you're experiencing difficulties with part: %s, %s; specifically, the report indicates that %s. Is that an accurate description of the problem? Firstly please accept my apologies on behalf of Blank for the difficulties you're experiencing with this part. As an ISO9001:2008 compliant organization, Blank takes all issues related to customer satisfaction very seriously. It is our intention to resolve this matter as soon as is possible.\n\n", name, partNum, sn, desc);
}
else
{
fprintf(fptr, "\nHi %s,\n\nI hope this message finds you well.\n\nI write to you today as the Quality Manager at Blank. I received a report that you're experiencing difficulties with part: %s; specifically, the report indicates that %s. Is that an accurate description of the problem? Firstly please accept my apologies on behalf of Blank for the difficulties you're experiencing with this part. As an ISO9001:2008 compliant organization, Blank takes all issues related to customer satisfaction very seriously. It is our intention to resolve this matter as soon as is possible.\n\nBefore I can begin an investigation into this problem, I'll need the serial number from that unit. Can you please forward me the serial number as soon as you're able? Once I have that, I can begin the investigation on our end. Thanks.\n\n", name, partNum, desc);
}
}
else if (strcmp(&ans2, "y")==0)
{
printf("Will Blank be sending the customer a replacement? Please enter y or n\n");
scanf("\n%c", &ansRep);
if (!strcmp(&ansRep, "y")==0)
{
fprintf(fptr, "Blank can send you a replacement product as soon as is possible. In order to ensure that the replacements are shipped to the correct address, will you please confirm you shipping address via email? Thanks.\n\n");
fprintf(fptr, "Thank you for your assistance in resolving this matter. Please let us know if you have any additional questions, comments, or concerns about this specific issue or any issues related to products distributed by Blank.\n\n");
fprintf(fptr, "Have a great day!");
}
else
{
fprintf(fptr, "Thank you for your assistance in resolving this matter. Please let us know if you have any additional questions, comments, or concerns about this specific issue or any issues related to products distributed by Blank.\n\nHave a great day!");
}
}
fclose (fptr);
return (0);
}
if (!strcmp(&ans1, "y")== 0) is wrong, which may be modified to if(ans1 != 'y'). You should do similar modifications to if (!strcmp(&ans2, "y")==0), if (strcmp(&ans2, "y")==0), if (!strcmp(&ansRep, "y")==0) in your code.
And for scanf("%c", &ans1);, you may rewrite it as follows:
scanf(" %c", &ans1);
Removing \n in scanf("\n%s" [...] and adding a space before %c in scanf("%c" and scanf("\n%c" (removing \n) may help.
you could create a simple function to catch strays from scanf
void clear_input_buffer(void)
{
char buffer[100];
fgets(buffer, 100, stdin);
}
then include it after scanf
scanf("%s", name);
clear_input_buffer();
First things first: ans1 and ans2 are chars; you are doing strcmp(&ans2, "y") - here, "y" is a string (NULL terminated array of characters) because it is in double quotes. Before anything else, you should replace all your comparisons of those variables with something like
if(ans1 == 'y')
Also, when you read a character you should add a space in front of the %c just in case there is some whitespace or a stray new line from previous input - scanf(" %c", &ans1);
Short answer: I think your strings contain garbage!
Strings in C must be terminated by a Null byte ('\0'). When you create a char array on the stack (or heap) the contents of that array may be filled with whatever junk your memory happened to have at the time. Try running this small program to see what I mean. One might predict this program will print 3 blank lines, but it should instead print 3 lines of random garbage (every time you run this program the garbage should be different).
#include <stdio.h>
int main(){
char name[32];
char partNum[32];
char desc[250];
printf("%s\n", name);
printf("%s\n", partNum);
printf("%s\n", desc);
}
There are a few things you could improve in the program you've posted, but to specifically address your string containing garbage, here is a simple solution:
Replace lines like char name[32]; to char *name = calloc(32, sizeof char); and be sure to free these memory allocations at the end of your program like this free(name).
calloc sets all the memory it allocates to NULL so your strings will no longer contain garbage.
If you are experiencing garbage in your output file, that should do the trick.
Also note
You are using fixed size char arrays. What happens if a user decides to type something in thats longer than you expected? The input will bleed into other parts of memory and can affect the values of other variables.

C - 3rd scanf modifies a variable from 2nd scanf

I think I've tried anything (flushing stdin, scanf to consume newline etc.), but nothing works as I had hoped. For some reason a 3rd scanf modifies a variable from 2nd scanf in the following code:
#include <stdio.h>
int main()
{
char first_name[16], last_name[21];
char filename[11];
FILE *opening;
printf("The program saves your first and last name into a file.\n");
printf("Enter your first name:");
scanf("%s", first_name);
getchar();
printf("Enter your last name:");
scanf(" %s", last_name);
getchar();
printf("File where you want to save your name:");
scanf(" %s", filename);
opening = fopen(filename, "wb");
fprintf(opening, "%s %s", first_name, last_name);
printf("\nSuccessfully saved the data!");
fclose(opening);
return 0;
}
The output:
The program saves your first and last name into a file.
Enter your first name: John
Enter your last name: Doe
File where you want to save your name: filename.txt
Successfully saved the data!
All fine and dandy except that the contents of filename.txt is this:
John t
I'm guessing that the 't' character comes from 'txt' somehow, but I've just started learning C and I don't know how to fix this piece of code to work. Could you gurus help me please?
Your filename buffer is too small.
You write filename.txt, which is 12 characters, plus the zero to finish it, makes 13. You only allocate 11. Try like this:
char filename[20];
and it should work.
Be careful though with using scanf, it can lead to very nasty problems, as you are encountering right now. It is good in experimenting and learning C, as it shows you how important correct memory handling is. For any real project you should consider using different functions or frameworks.
Using scanf() on strings is dangerous, as it may read in more data into the buffer than the buffer provides memory.
If scanning in strings one shall always tell scanf() how much characters to read by adding this number to the format passed to scanf():
char file_name[11];
...
scanf("%10s", file_name); /* As file_name provides memor for 11 characters, read a
maximum of 10 characters into file_name leaving 1
character room for the necessary `0-`terminator indicating
the end of the "string". */
Also your code misses error checking on the fopen system call.
Better do something like this:
opening = fopen(filename, "wb");
if (NULL == opening)
{
perror("fopen() failed");
exit(EXIT_FAILURE);
}
If you are entering filename.txt as your file name, then you are overrunning your buffer for filename. That is undefined behaviour and is the cause of the strange results.
To fix, make char filename[11]; larger, remembering to allow 1 extra character for the NULL terminator. In your very specific case, that would be char filename[14]; allowing for the errant space before %s in your scanf call.
Otherwise, all looks fine.

Resources