strcmp() not returning what it should return - c

Basically I want to create a program that would have potential questions that might be in my upcoming exam in Digital Systems.
#include <stdio.h>
#include <string.h>
int main() {
char input1[600];
printf("What is the set of available registers?");
scanf("%s", &input1);
if(strcmp(input1, "registers, memory, hard disc") == 0){
printf("Good job! You got it right");
}
else {
printf("Wrong answer!");
}
So whenever I type "registers, memory, hard disc" when I'm asked it returns 1 instead of 0. I cannot see the problem. I am kind of new to C so sorry if it is a silly question.

As already said in the comments, scanf() with "%s" stops conversion at the first whitespace character. To read a whole line of text, use fgets():
#include <stddef.h>
#include <stdio.h>
#include <string.h>
// ...
char foo[100];
if(!fgets(foo, sizeof(foo), stdin)) // don't use sizeof on pointers
; // handle error // for that purpose!
size_t length = strlen(foo);
if(length && foo[length - 1] == '\n') // fgets also reads the newline character
foo[--length] = '\0'; // at the end of the line, this removes it.

Swordfish has already given a good answer, and fgets is preferable to scanf. However, I want to show how you would use scanf in this case:
if(scanf("%599[^\n]", input1) != 1) {
// Handle error
}
So what is different?
scanf returns the number of successfully assignments, so if this returns 1, then input1 has been assigned. If not, an error has occured.
Changed s to [^\n] to read until newline
Inserted 599 (one less than 600) so ensure that we don't write outside the array.
Removed & from input1. In this case, it would probably work anyway, but it is undefined behavior, which should be avoided at all costs.

Try change your scanf line from:
scanf("%s", &input1);
to:
scanf("%[^\n]", input1);
It worked out for me.

Related

scanf read variable number of characters

I was wondering how I can get scanf to skip reading a character if I press enter... My code is the following:
#include <stdio.h>
int main(void)
{
int a, status;
char b;
printf("Please enter a positive number immediately"
"followed by at most one lower-case letter:\n\n");
status = scanf("%i%c", &a, &b);
if (status == 1 && getchar() == '\n') {
printf("\nThank you!\n");
}
return 0;
}
When I enter just a number and nothing else, I need to press enter again to trigger the %c, &b in scanf. How do I avoid that and get the program to accept just 1 number to jump to the printf?
I tried:
if (status == 1 && getchar() == '\n')
but that won't work.
As noted in the comments, your best course of action is to use fgets to just read in a string, then parse and validate it. This Thread will provide you with enough resources for you to educate yourself about the use of fgets.
Here is one approach you can take. Please note that this code does not attempt to validate every possible input a user can provide, but rather give you a reasonable direction you can take to solve your problem if the input is assumed correct. I will leave the task of validation to you. The code below should provide enough tools to accomplish the rest of your task. Look at using a for loop to step through the buffer and ensure the input is correct. Use isalpha() and isdigit() to test each character. You can also implement your own functions to test each character as is done
in this answer.
#include <stdio.h>
#include <stdlib.h> //for atoi()
#include <string.h> //for strlen()
#include <ctype.h> //for isalpha()
#define MAX_INPUTLENGTH 500
int main(void)
{
//Always a good idea to initialize variables to avoid Undefined Behaviour!
char buffer[MAX_INPUTLENGTH] = { '\0' };
int a = 0, status = 1, length = 0;
char b = '\0';
printf("Please enter a positive number immediately"
"followed by at most one lower-case letter:\n\n");
//this gets you a string you can work with
fgets(buffer, sizeof(buffer), stdin);
length = strlen(buffer);
buffer[length - 1] = '\0';//remove the trailing '\n'
length--;
//now see if last character is a letter
if (isalpha(buffer[length - 1])) {
b = buffer[length - 1];//then assign and..
buffer[length - 1] = '\0';//trim the letter
}
//this function converts the remaining string to an int
a = atoi(buffer);
//Use the debugger and observe how these functions work in order
//to validate the input. for now, status is always 1!
if (status == 1) {
printf("\nThank you!\n");
}
return 0;
}
As noted in the comments below by #Jonathan, to portably get the count of an array, one should use sizeof(buffer) / sizeof(buffer[0]). Since you are using a char[], sizeof(buffer[0]) evaluates to 1, thus can be omitted when calling fgets.

Reading until I manage to enter an integer

I'm pretty new in C, I used to work in Python, and I'm trying to see if something that I read is integer number. If not, to read until I manage to entry a number.
I did some research and I found out that the function scanf actually returns 1 if the read is done suitably, and 0 otherwise.
So, I have written this code, and I don't understand why this is an infinite loop, writing "Give an integer" on the console
#include <stdio.h>
int main() {
int a;
int b = 1;
do {
printf("Give an integer\n");
b = scanf("%d", &a);
} while (b == 0);
}
The problem with scanf() is that it stops reading when the first white space is encountered for most specifiers like "%d", so it's left in the input and that's why reading again would cause a problem if you don't discard such white space because it will then return immediately the next time you call it. There is a mandatory white space that is introduced when you press Enter or Return, the '\n' new line character (or line feed).
If you want to read an integer and make sure you did you can try like this
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int
main(void)
{
long int value; // You can adapt this to use `int'
// but be careful with overflow
char line[100];
while (fgets(line, sizeof(line), stdin) != NULL) {
char *endptr;
value = strtol(line, &endptr, 10);
if ((isspace(*endptr) != 0) && (endptr != line))
break;
}
fprintf(stdout, "%ld\n", value);
return 0;
}
read strtol()'s manual to understand this code
You could as suggested in the comments, remove the white space characters from the input, but IMHO that is harder and you would still have other problems with scanf(), like handing empty input which is not straight forward.
I don t understand why this is an infinite loop, writing "Give an intiger" on the console
The problem is that scanf() does not consume data that it cannot match against the specified format. It leaves such characters unread in the input stream. Therefore, if you try reading again from the same stream with the same format, without consuming at least one character by some other means, then you can be certain that the input will again not be matched. And again. And again.
To avoid your infinite loop, you need to consume at least one character of the non-matching input after each matching failure. There are many ways you could do that; here's a fairly simple one:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
if (scanf("%d", &a)) {
// breaks from the loop on a successful match or an error
break;
}
// consume the remainder of one line of input without storing it
if (scanf("%*[^\n]") == EOF) {
break;
}
} while (1);
}
That consumes the whole remainder of the line on which the non-matching input is encountered, which will yield less surprising interactive behavior for some inputs than many alternatives would.
If you've a penchant for writing terse code, or if you don't like to break out of the middle of a loop, then you might write the same thing like this:
#include <stdio.h>
int main() {
int a;
do {
printf("Give an intiger\n");
} while ((scanf("%d", &a) == 0) && (scanf("%*[^\n]") != EOF));
}
Because the && operator short circuits, the second scanf() call will be executed only if the first returns zero, and the loop will exit after the first iteration wherein either the first scanf() call returns nonzero or the second returns EOF (indicating an error).

C while loop feof

This is part of a much bigger program to make a filmgenie and for some reason the program crashes as it reaches this while loop and i don't understand what my problem is.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
FILE *fp, *fopen();
char *arrayoffilms[45];
int main()
{
char line[100],junk[100];
fp=fopen("filmtitles.txt","r");
int i=0;
while(!feof(fp)) {
fscanf(fp,"%[^\n]s",line);
strcpy(arrayoffilms[i],line);
fscanf(fp,"%[\n]s",junk);
i++;
}
fclose(fp);
printf("%s\n\n\n",arrayoffilms[i]);
return 0;
}
feof will never return true until an actual read attempt is made, and EOF has been reached. The read attempts usually have return values that indicate failure. Why not use those, instead?
Don't confuse the %[ and %s format specifiers; %[ doesn't provide a scanset for %s; %[^\n]s tells scanf to read "one or more non-'\n' characters, followed by a 's' character". Does that make sense? Think about it, carefully. What is the purpose of this format specifier? What happens if the user merely presses enter, and scanf doesn't get it's "one or more non-'\n' characters"? Before we look for non-'\n' characters, it's important to get rid of any '\n' characters. Any whitespace bytes in the format string will cause scanf to consume as much whitespace as possible, up until the first non-whitespace character. I'm going to presume you wanted %[^\n], or perhaps even %99[^\n], which would prevent overflows of line.
Perhaps you'd also want to count the number of bytes processed by scanf, so you can malloc the correct length and copy into arrayoffilms, for some reason I can't imagine. You can use the %n format specifier, which will tell you how many bytes scanf processed.
I noticed that you want to read and discard the remainder of a line. In my example, the remainder of a line will only ever be discarded if 99 characters are read before a newline is encountered. I'll use the assignment suppression '*': %*[^\n].
Combining these format specifiers results in a format string of " %99[^\n]%n%*[^\n]", two arguments (a char * for %[ and an int * for %n), and an expected return value of 1 (because 1 input is being assigned). The loop will end when the return value isn't 1, which will likely be caused by an error such as "reading beyond eof".
int length;
while (fscanf(fp, " %99[^\n]%n%*[^\n]", line, &length) == 1) {
arrayoffilms[i] = malloc(length + 1);
strcpy(arrayoffilms[i], line);
i++;
}
The problem might be about the feof. You want your while loop to terminate when you reach the end of the file, or in other words, when you can not get anything using fscanf.
You can go for the code below:
while(fscanf(fp,"%[^\n]s",line)) {
strcpy(arrayoffilms[i],line);
fscanf(fp,"%[\n]s",junk);
i++;
}
Also, error checking associated with file pointers is absolutely necessary and is a good habbit. You would definitely want to use it:
fp=fopen("filmtitles.txt","r");
if(fp == NULL) /* error handling */
printf("Could not open file: filename\n");
else{
/* do stuff */
}
A similar thing happens with fgets() so some people say to never use it. Look at it this way, if you say
while (!feof(ipf)) {
by the time feof() is true you've hit the end of the file. The byte you just read is garbage, maybe a NULL. Don't use it. This works:
while (!feof(ipf)) {
if (!feof(ipf)) {
ch = fgetc(ipf);
And it works for fgets() too, I've used it this way for years. If this were Pascal (or maybe Perl) and you read "until" feof that would work, it's a pre-test vs a post-test issue. So test twice.

A Way to deal with this input?

I'm trying to identify a way in which when data is input like such:
Name Integer
Name Integer
Name Integer
.
Each time the Name and Integer are entered, and a newline is detected, stuff is done with that name and integer, then again, and again, until the '.' is detected.
I've tried getchar() loops, and IF statements to detect '\n' for example, but none seem to work. Any ideas?
What about using scanf()?
scanf("%s %d\n", my_string, &my_int);
http://linux.die.net/man/3/scanf
scanf("%s%d\n", name, &intVar);
if((*name=='.') && (*(name+1)=='\0')){
return 0;
}
this should be suffice
How about:
#include <string.h>
#include <stdio.h>
int main()
{
char input[30];
gets(input);
while(strcmp(input, ".") != 0)
{
// do stuff
gets(input);
}
return 0;
}
Don't use scanf directly. It's surprisingly hard to use. It's better to read an entire line of input (for example, with fgets) and to then parse it (possibly with sscanf).

C Programming Input Error

int main(void) {
char *input;
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
prompt>input
RUN FAILED (exit value 138, total time: 3s)
What's wrong with the code? Has to be either the scanf() or the second printf(). The input is of unknown length. A lot people have said to simply create a char array of length 'X' to hold the input. Just wanted to know then why this code works.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
Your specific problem is that you have no storage behind input. It's an uninitialised pointer, pointing to a random spot in memory, which is unlikely to be anywhere useful.
You can use something like:
char *input = malloc (100);
// check that input != NULL
// use it
free (input);
or:
char input[100];
but you have a serious problem with your use of scanf (see below).
You should never use an unbounded %s in scanf (or any of its variants unless you totally control the input). It's a dangerous practice prone to buffer overflows and the sooner you get out of the habit, the better. It's akin to gets() in that way.
From an earlier answer of mine, this piece of code below (along with your main code incorporated into it) provides a safe way of getting user input. You pass in an optional prompt, the buffer to load the input into, and the size of the buffer.
It will return the input up to the size of the buffer (stripped of the newline if there) then clear out the rest of the line if necessary so that it doesn't affect the next input operation. It will return either OK or an error indication on end-of-file or if the input was too long (you still get the first part of the input in case you want to do something with it).
Once you have the line, you can sscanf it, safely, to your heart's content. However, that's not required in your case since you're only trying to get a string. Just use the buffer that's returned directly.
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
int main(void) {
char input[10];
int rc = getLine ("prompt> ", input, sizeof (input));
switch (rc) {
case NO_INPUT: printf ("\nNo input recieved\n"); break;
case TOO_LONG: printf ("Too long, truncated input below:\n");
default: printf("Your input was [%s]\n", input);
}
return 0;
}
Give that a shot, it's far more robust than using scanf("%s") on its own.
As for your update asking why this works:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
/* prompt */
char input;
printf("prompt>");
scanf("%s", &input);
printf("%s", &input);
return 0;
}
It's undefined code. Period. You only allocate space for a character but you scan in a string. Since a string is a character array of all the characters followed by a zero character, the only string you could input safely there would be an empty one.
Anything else will write to both the character and whatever happens to be adjacent to the character on the stack.
This is no different to allocating char input[100] then entering 200 characters, it's still buffer overflow and should be avoided.
Discussion below is based on a particular implementation of C, not necessarily all implementations.
Chances are, you got lucky here. Compilers may generate code that keeps the stack pointer aligned so that, even though you asked for one byte, you may get space allocated for four (or even more, depending on the architecture - I'll assume most types are four bytes here for simplicity).
In addition, you may find that you can also safely overwrite the eight bytes of argc integer and argv pointer (they're probably still there even though you don't use them, no point having two different sets of start-up code just to save a few bytes on the stack).
If you write further than that, you'll eventually overwrite the return address from main to your start-up code. Then you'll know about it since your code will go off into la-la land when main exits.
With undefined behaviour, anything can happen. Sometimes that anything includes the possibility that it will work perfectly (similar to "throw a deck of cards in the air often enough and they'll eventually fall in a nice neat sorted heap" but a little less random).
That does not make undefined behaviour any less of a bad thing.
char *input;
Is only a pointer - there is no data space allocated store the data that scanf collects.
try this instead
char input[100];
You may want to try scanf("%c", input) inside of a while loop that has your delimiting character. You should also make input an array char input[X] where X is a number of sufficient value to hold the most likely values for your input. I would try making input an array first though.
You forgot to allocate the memory before using your pointer.
Try it:
int main(void) {
char input[256];
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
or even:
#include <stdlib.h>
#include <stdio.h>
int main(void) {
char *input = (char *) malloc(sizeof(char) * 256));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
return 0;
}
What compiler do you use? In Turbo C 3.0 it works.
Try this variant:
#include <stdio.h>
#include <alloc.h>
int main(void)
{
char *input = (char*)calloc(100, sizeof(char));
printf("prompt>");
scanf("%s", input);
printf("%s", input);
free(input);
return 0;
}
Try:-
int main(void) {
char input[100];
printf("prompt>");
scanf("%99s", input);
printf("%s", input);
return 0;
}
This will limit the string to 99 bytes. Note "%s" == string of characters delimited by white space or newline ie. you only get the first word!
I think what you really want is:
#include <stdio.h>
int main(void) {
char input[99];
printf("prompt>");
fgets(input,99,stdin);
printf("->%s<-", input);
return 0;
}
You probably need to add some code to get rid of unwanted new line characters!

Resources