Can't detect the end of input strings - arrays

This is to perform function of a phone book getting names and their phone number. For requested names it must print their phone number. The last out line prints infinitely for I cannot detect the end of input. I have used \n, ' ' and, " ", but nothing works. HELP!
#include <stdio.h>
struct ph_book{
char name[100000];
double ph;
}p[20];
int main() {
char temp[100000],ex[100000];
int n,i,flag=0;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s",p[i].name) ;
scanf("%lf",&p[i].ph);
}
scanf("%s",temp);
while(temp[0]!='\n'){
flag=0;
for(i=0;i<n;i++){
if(strcmp(temp,p[i].name)==0){
printf("%s=%.lf\n",p[i].name,p[i].ph);
flag=1;
break;
}
}
if (flag==0){
printf("Not found\n");
}
strcpy(ex,temp);
scanf("%s",temp);
if (strcmp (temp, "\n") == 0)
break;
}
return 0;
}/* Enter your code here. Read input from STDIN. Print output to STDOUT */

The "\n" is not part of the input string of scanf function.
The following code will not enter the break (conditions is always be FALSE).
if (strcmp (temp, "\n") == 0)
break;
If you wish to terminate input by empty string (when user press enter),
The following should work:
Replace scanf with gets (or better use the safe version: gets_s).
Compare temp[0] to zero, for detecting end of input sequence.
Sample code:
gets_s(temp, sizeof(temp)); //Instead of scanf("%s",temp);
while (temp[0] != 0)
{
strcpy(ex, temp);
gets_s(temp, sizeof(temp)); //Instead of scanf("%s",temp);
if (temp[0] == 0)
break;
}

Related

Is there a way of limiting scanf in C?

I am trying to write a correct console application for linked list usage, so i need to scan a number of a command in a infinite loop and do something due to switch case option. So i am using scanf for this but the problem is when the next line doesnt contain number it loops and starts printing not even default value.
`while(1)
{
printf("Enter a number of a command.\n");
scanf("%d",&command);
switch(command)
{
case -1:
....
default:
printf("Reenter command.\n");
break;
}
}
It seems like when i am reading the infinite amount of data stack gets rewrited. I know i have to limit the amount of symbols reading, but dont understand how to do this in right way.
Using gcc version 5.4.0 (GCC), c99 on Ubuntu 18.04.2 LTS
I don't have enough reputation to comment, but this might be what you are looking for. Also try to be more descriptive. I have pasted your code and the only problem I could find is that when you press enter without inserting a number(i.e. a letter) it skips. This should fix it:
int readInt(const char *message, int min, int max){
int num, control;
do{
printf("%s (%d a %d) :", message, min, max);
control = scanf ("%d", &num);
cleanBufferStdin();
if (control == 0)
{
printf("You should enter a number \n");
}
else{
if(num<min || num>max)
{
printf("Number is invalid.\n");
}
}
}
while(num<min || num>max || control ==0);
return num;
}
void cleanBufferStdin(void)
{
char chr;
do
{
chr = getchar();
}
while (chr != '\n' && chr != EOF);
}
I coded for a bit more, and in another interpretation of your question(this one not only detects if you just pressed enter but if you didnt place an integer i didnt check if negative numbers work) I used this function:
//DONT FORGET TO #DEFINE WRONG_REQUEST_MACRO "SOME MESSAGE"
void readString(const char message*, char arrayChars *, int maxChars){
int stringSize;
unsigned char flag=0;
do{
flag =0;
printf("%s", message);
fgets(arrayChars, maxChars, stdin);
stringSize = strlen(arrayChars);
if (stringSize == 1){
printf("[INFO]Empty request. You just pressed ENTER.\n");
flag=1;
}
if (atoi(arrayChars)==0&&arrayChars[0]!=0){
printf("[INFO]You didn't enter a number.\n");
flag=1;
}
} while (flag == 1);
if (arrayChars[stringSize - 1] != '\n'){
clearBuffer();
}else{
arrayChars[stringSize - 1] = '\0';
}
while (strchr(arrayChars, '\'') != NULL || strchr(arrayChars, '?') != NULL || strchr(arrayChars, '*') != NULL || strchr(arrayChars, '\"') != NULL){
printf("%s ' %s '", WRONG_REQUEST_MACRO, arrayChars);
break;
}
}
this should be used like
int command;
char message[20];//yes this could be used with a char pointer but lets assume op doesnt know how to allocate memory or work with char pointers it wouldn't change that much but if he does know how to do it he will promptly change
readString("something something i suppose\n",message,20);
command=atoi(message);
Welp the last although its filled with debugging "duplicates" should work

Check if string is empty, then continue

I'm creating a very basic shell. When the user hits enter without typing any commands, the program should go to next line and continue.
If the user type any command, the program should print a text message.
I'm having issues with the empty string condition.
Tried strcmp() with another char array.
#include <stdio.h>
#include <string.h>
int main(void){
char input[256];
char str[4] = {"exit"};
do
{
printf("CSC327> ");
scanf("%[^\n]", &input);
if(getchar() == '\n')
continue;
if(strcmpi(input, str))
printf("Command not found!\n");
}while(strcmpi(input,str));
printf("\nGoodbye.");
return 0;
}
If you want to check if a string is empty, just use
int lenght = strlen(your_string)
The length of the string is returned. If it is 0, the string is empty.
First the working version of code here!.
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int my_strcmp(char *a, char *b)
{
while(*a == *b){
a++;
b++;
}
///check line ending
if (*a == '\n' && *b=='\0')
return 0;//are equal
return 1;
}
int main(void)
{
char input[256]; //Array of characters for user input
int flag = 1;
do
{
printf("CSC327> ");
fgets(input, 256, stdin); //Read user input
if(*input == '\n')
continue;
if(my_strcmp(input, "exit")){ //Compare temp with 'exit' case insensitive
printf("Command not found!\n");
}
else{
printf("Ok! Exiting\n");
flag=0;
}
}while(flag);
printf("\nGoodbye.");
return 0;
}
Main problem is in strcmp() function. I prefer to write a simple version under the name of my_strcmp() to work exactly in this question.
Consider last character of string source and destination.
source ending is '\n' and destination is '\0'.
An ugly version to do this comparison used here. my_strcmp() can be very better but now just enough.
You call strcmp() two times, by using a flag one of them can be remove.
As Steve Summit say at comment we can use if(*input == '\n') continue; instead of your way.
Related link about writing a shell
Tutorial Write a Shell in C by Stephen Brennan, GitHub
Making your own Linux Shell in C
Want to build a simple shell? Here’s how you do it.
In brenns shell Consider line 187 if (position >= bufsize) as Steve Summit say in comment you must handle a situation if user input a larger buffer input.
Take a look at ASCII table that guide me to find out why builtin strcmp() not work properly because of different line ending 10 vs. 0.
Edit
Use '\n' instead of 10 as suggested in comment
my_strcmp() not work as case intensive compare I will improve it soon.
fgets() add \n line feed character at the end of inputted string. i.e: input[last]= '\n'. But char s[] = "test" adds '\0'
at the end of string s. For this we cant compare simply these string with library functions for example strcmp and others.
change this character and use library function strcasecmp()
By this do while loop can be rewrite
do
{
printf("CSC327> ");
fgets(input, 256, stdin); //Read user input
//fgets add \n at the end of string
/// "salam" add \0 at end of string
///change last char
input[strlen(input)-1]='\0';
//printf("len: %ld", strlen(input));
if(*input == '\n')
continue;
if(strcasecmp(input, "exit")){ //Compare temp with 'exit' case insensitive
printf("Command not found!\n");
}
else{
printf("Ok! Exiting\n");
flag=0;
}
}while(flag);
printf("\nGoodbye.");
return 0;
}
int main()
{
char input[256]; //Array of characters for user input
char temp[4]; //Array of 4 characters for getting the first 4 characters of input
do
{
printf("CSC327>");
fgets(input, 256, stdin); //Read user input
strncpy(temp, input, 4); //Get first 4 characters of input
if(strlen(input) == 1) //Determine if input is empty
continue;
if(strcmpi(temp, "exit")) //Compare temp with 'exit' case insensitive
printf("Command not found!\n");
}
while(strcmpi(temp, "exit"));
printf("\nGoodbye.");
return 0;
}//main ends

How do i remove NULL input in C?

My teacher has asked me to "Fool proof" my code from any sort of misuse, So I have come up with an
program that can remove any empty values (by disallowing them entirely)
Here is the Un-foolproofed code
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
printf("Type something: ");
fgets(text,16, stdin);
printf("You typed: %s",text);
getch();
}
I have made some simple adjustments to ensure there is no error, however, i cannot get the if filter to work properly, as it still allows the NULL input
#include <stdio.h>
#include <conio.h>
int main()
{
char text[16];
int loop;
do
{
printf("Type something: ");
fgets(text,16, stdin);
if( text[0] == '\0')
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}
}
while(loop > 0);
printf("You typed: %s",text);
getch();
}
I've tried google and i cannot get a solid answer, this probably is some very simple line of code, but sadly i have no idea what it is.
Edit: it's fixed, the if statement should be:
if (text[0] == '\n')
Using the return value from fgets() is the best first step to fool-proofing user I/O.
char text[16];
printf("Type something: ");
if (fgets(text, sizeof text, stdin) == NULL) {
if (feof(stdin)) Handle_stdin_is_closed(); // no more input
if (ferror(stdin) Handle_IOerror(): // very rare event, more common with files
}
// Test is input is is only a '\n'
if (text[0] == '\n')
printf("Try again");
// Look for long line.
size_t len = strlen(text);
if (len + 1 == sizeof text && text[len - 2] != '\n') HandleLongLine();
The next step is to look for scan errors. Let's assume code is to read a long.
errno = 0;
char *endptr;
long = strtol(text, &endptr, 10);
if (errno) Handle_NumericOverflow();
if (text == endptr) Handle_InputIsNotNumeric();
while (isspace((unsigned char) *endptr)) endptr++;
if (*endptr != '\0') Handle_ExtraTextAfterNumber();
Although this is a lot of code, robust handling of hostle user input is best spun off to a helper function where lots of tests can be had.
char * prompt = "Type something: ";
long number;
int stat = GetLong(stdin, prompt, &number); // put all tests in here.
if (stat > 0) Handle_SomeFailure();
if (stat < 0) Handle_EOF();
printf("%ld\n", number);
fgets reads a whole line including the newline into the buffer and 0-terminates it.
If it reads something and then the stream ends, the read line will not have a newline.
If the line does not fit, it won't contain a newline.
If an error occurs before it successfully reads the first character, it returns NULL.
Please read the man-page for fgets: http://man7.org/linux/man-pages/man3/fgets.3.html
According to the fgets() man page
char *fgets(char *s, int size, FILE *stream);
//fgets() returns s on success, and NULL on error or when end of file
//occurs while no characters have been read.
so, you can check the return value of fgets()
n = fgets(text,16, stdin);
if that value is NULL, then nothing have been read.
you can do this by checking the value of n in a for loop,
if( n == NULL)
{
printf("Try again");
system("cls");
loop=1;
}
else
{
loop = -1;
}

scanf validation sits and waits for another input. Why?

I was working on this sample exercise, and everything works as I would like it to, but there is one behavior I don't understand.
When providing input: if I make consecutive invalid entries everything seems to work great. But if I enter a number different from 1,2,3 in the case of the first question, or 1,2 in the case of the second question, the program just sits there until a new input is given. If another invalid entry is made, it goes back to the error "invalid entry" message, and if an appropriate number is entered, everything moves along fine.
I do not understand why it stops to wait for a second input...anyone?
Thanks guys.
#include <stdio.h>
static int getInt(const char *prompt)
{
int value;
printf("%s",prompt);
while (scanf("%d", &value) !=1)
{
printf("Your entry is invalid.\nGive it another try: %s", prompt);
getchar();
scanf("%d", &value);
}
return value;
}
int main() {
int wood_type, table_size, table_price;
printf("Please enter " );
wood_type = getInt("1 for Pine, 2 for Oak, and 3 for Mahogany: ");
printf("Please enter ");
table_size = getInt("1 for large, 2 for small: ");
printf("\n");
switch (wood_type) {
case 1:
table_price = (table_size == 1)? 135:100;
printf("The cost of for your new table is: $%i", table_price);
break;
case 2:
table_price = (table_size == 1)? 260:225;
printf("The cost of for your new table is: $%i", table_price);
break;
case 3:
table_price = (table_size == 1)? 345:310;
printf("The cost of for your new table is: $%i", table_price);
break;
default:
table_price = 0;
printf("The cost of for your new table is: $%i", table_price);
break;
}
}
You most likely need to flush your input buffer (especially with multiple scanf calls in a function). After scanf, a newline '\n' remains in the input buffer. fflush does NOT do this, so you need to do it manually. A simple do...while loop works. Give it a try:
edit:
static int getInt(const char *prompt)
{
int value;
int c;
while (printf (prompt) && scanf("%d", &value) != 1)
{
do { c = getchar(); } while ( c != '\n' && c != EOF ); // flush input
printf ("Invalid Entry, Try Again...");
}
return value;
}
The blank line you get if you enter nothing is the normal behavior of scanf. It is waiting for input (some input). If you want your routine to immediately prompt again in the case the [Enter] key is pressed, then you need to use another routine to read stdin like (getline or fgets). getline is preferred as it returns the number of characters read (which you can test). You can then use atoi (in <stdlib.h>) to convert the string value to an integer. This will give you the flexibility you need.
example:
int newgetInt (char *prompt)
{
char *line = NULL; /* pointer to use with getline () */
ssize_t read = 0; /* number of characters read */
size_t n = 0; /* numer of chars to read, 0 no limit */
static int num = 0; /* number result */
while (printf ("\n %s ", prompt) && (read = getline (&line, &n, stdin)) != -1)
{
if ((num = atoi (line)))
break;
else
printf ("Invalid Input, Try Again...\n");
}
return num;
}
If some invalid input is entered, it stays in the input buffer.
The invalid input must be extracted before the scanf function is completed.
A better method is to get the whole line of input then work on that line.
First, put that input line into a temporary array using fgets(),
then use sscanf() (safer than scanf because it guards against overflow).
#include <stdio.h>
int main(int argc, const char * argv[]) {
char tempbuff[50];
int result, d , value;
do
{
printf("Give me a number: ");
fgets( tempbuff, sizeof(tempbuff), stdin ); //gets string, puts it into tempbuff via stdin
result = sscanf(tempbuff, "%d", &value); //result of taking buffer scanning it into value
if (result < 1){ //scanf can return 0, # of matched conversions,
//(1 in this case), or EOF.
printf("You didn't type a number!\n");
}
}while (result < 1);
//some code
return 0;
}
Knowledge from: http://www.giannistsakiris.com/2008/02/07/scanf-and-why-you-should-avoid-using-it/

Trying to take multiple string inputs

Practice.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARR 32
int main(void){
int MEM=64;
char arr[ARR],*p=(char *)calloc(MEM,(sizeof(char))),*q=NULL;
int i=0,j=1;
printf("\nEnter String : ");
while(j){
scanf(" %[^\n]s " ,arr);
if(j==1)
strcpy(p,arr);
else
strcat(p,arr);
if((j*ARR)==MEM){
MEM=MEM+(j*ARR);
q=realloc(p, MEM);
if(!(q)){
printf("\nNOT ENOUGH MEMORY\n");
goto END;
}
p=q;
}
for(i=0;i<(strlen(arr));++i){
if(arr[i]=='\n')
break;
}
if(arr[i]=='\n')
break;
++j;
}
printf("\n %s\n",p);
END: free(p);p=NULL;q=NULL;
return 0;
}
I am trying to get multiple string inputs.
I am using scanf(" %[^\n]s",arr); to take the input instead of fgets(arr,ARR,stdin);, because with fgets the program execution stops as soon as I hit ENTER key. But with scanf(" %[^\n]s",arr); the program is unable to get out of the while() loop even after entering \n.
I would like to know the mistake or mistakes I have made while writing the code.
The canonical way of reading multiple lines of input in C is to use fgets in a loop, like
while (fgets(arr, sizeof(arr), stdin) != NULL)
{
if (arr_contains_special_input_to_exit_loop(arr))
break;
// Optionally check for and remove trailing newline from input
// Append `arr` to your data
}
The condition to exit the loop might be some special input or an empty line or something else completely.
One mistake is:
for(i=0;i<(strlen(arr));++i){
if(arr[i]=='\n')
break;
}
Looking earlier in you code you have:
scanf(" %[^\n]s " ,arr);
The [^\n] prevents any newlines \n from being contained in arr. So your loop that looks for (arr[i]=='\n') will never find any. Your next bit of code continues looking for non-existent newlines:
if(arr[i]=='\n')
break;
This last break also breaks out of your outer loop preventing you from asking for further input on finding a newline (which it shouldn't). Fix these issues and it should get much further allowing you to enter multiple items.
Edit:
With a bit of effort looking at what you were doing, I now have it taking multiple input and reallocating as necessary. The strings are all concatenated and printed at the end. It could still stand a bit of work, but this should give you a few hints:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARR 32
int main (void) {
int MEM = 64;
char arr[ARR], *p = (char *) calloc (MEM, (sizeof (char))), *q = NULL;
int i = 0, j = 1;
while (j) {
printf ("\nEnter String : ");
scanf (" %[^\n]s ", arr);
printf (" you entered (arr): %s\n", arr);
if (strcmp (arr, "q") == 0) {
printf ("\n 'q' entered, exiting.\n\n"); // provide for exit if `q` entered
break;
}
if (j == 1)
strcpy (p, arr);
else
strcat (p, arr);
if ((j * ARR) == MEM) {
MEM = MEM + (j * ARR);
q = realloc (p, MEM);
if (!q) {
printf ("\nNOT ENOUGH MEMORY\n");
goto END;
}
else
printf ("\nMemory Reallocation - succeeded.\n");
p = q;
}
++j;
}
printf (" %s\n", p);
END:
if (p) free (p); /* always test pointer before calling free */
p = NULL;
q = NULL;
return 0;
}
output:
./bin/me
Enter String : fishinsea
you entered (arr): fishinsea
Enter String : alligators
you entered (arr): alligators
Memory Reallocation - succeeded.
Enter String : really_big_mosters
you entered (arr): really_big_mosters
Enter String : SuperSnake_Prudhome
you entered (arr): SuperSnake_Prudhome
Memory Reallocation - succeeded.
Enter String : 8_puppies
you entered (arr): 8_puppies
Enter String : q
you entered (arr): q
'q' entered, exiting.
fishinseaalligatorsreally_big_mostersSuperSnake_Prudhome8_puppies

Resources