Scanf won't notice '\n' char in a program loading only numbers - c

I have been searching for a few days and I have found only one solution that didn't look perfect to me. Our teacher asked us to create a function that would calculate total lenght of distances in between points provided by user.
My idea was to write code this way, using an array of specific type.
The issue is that, I can't come up with any ideas for how to solve the issue with input: He asked us to make the program end once the user doesn't type anything, so I take it for enter - \n sign.
I could use fgets to get the first variable but:
First, I feel like I don't know any other way beside an array for keeping a long decimal number(in a form of a char array with elements making up the number), that the user could put on the input. I don't know if his script doesn't put some "rofl" number in there.
Second, in this case I think that stripping that array off one X would totally break the total structure of this program. I would rather take both X and Y and accept them as char type, but then the function like atof would probably understand only the X and would stop working after the \n sign.
So Y would be left not given. The accepted input numbers should be of double type. Like:
2 2
3 3
-2 4.5
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
double lenght(struct point *coordinates, int n);
struct point {
double x;
double y;
};
int main()
{
double x,y,TwiceAsBig=3;
int i=0,l=0;
struct point *coordinates;
coordinates = (struct point*)malloc(sizeof(*coordinates)*3);
//allocation of memory for pointtype array with a pointer
while(scanf("%lg %lg",&x,&y)==2)
{
coordinates[i].x=x;
coordinates[i].y=y;
i++;
if(i==TwiceAsBig)
{
coordinates = (struct point*)realloc(coordinates, 2*i*sizeof(*coordinates));
TwiceAsBig=2*TwiceAsBig;
}
}
printf("\n");
for(l;l<i;l++)
{
printf("%lg %lg\n", coordinates[l].x,coordinates[l].y);
}
//checking on the array if the values were loaded correctly
printf("%lg",lenght(coordinates,i));
}
//function for dinstace in between the points
double lenght(struct point*coordinates,int n)
{
int l=0;
for(l;l<n;l++)
{
printf("%lg %lg\n", coordinates[l].x,coordinates[l].y);
}
int pair=0;
double lenght,distance;
for(int AoP;AoP<n-1;AoP++)
{
distance=sqrt(pow(coordinates[pair+1].x-coordinates[pair].x,2)+pow(coordinates[pair+1].y-coordinates[pair].y,2));
pair++;
printf("%lg: ", distance);
lenght=lenght+distance;
}
return lenght;
}

As for your problem, using fgets to read a whole line, and the possibly use sscanf to parse out the two numbers might work.
The problem with using only scanf is that all the numeric format specifiers reads and skips leading white-space automatically, and newline is a white-space character. That means your scanf call in the loop condition will wait until there's some actual non-space characters being input (followed by a newline of course, which leads to the cycle starting over again).

What about using scanf("%[^\n]%*c", test); to read a full string.
Then parsing the result using sscanf?
Something like this:
char* userinput = (char*) malloc(sizeof(char) * 100);
scanf("%[^\n]%*c", userinput);
double a, b;
sscanf(userinput, "%lg %lg", &a, &b);
printf("sum %lg\n", a+b);
With input "-5.5 3.2" the code produces "sum -2.3".
%[^\n]%*c is a "scanset" which tells scanf to read everything excluding '\n' and once it reaches a newline it reads the newline character and disregards it.
You could even use scansets to check the input to some degree by specifying which type of characters you expect to read.
%[0-9 .\\-] // would read digits from 0-9, 'space', '.' and '-'

Related

Using scanf to read an integer with nothing else but a newline character

Is there a way to use scanf (without using any other I/O function) to check whether the user input exists only of a single integer with nothing following it?
For example:
int g;
while(scanf("%d", &g)!=1){
printf("\nincorrect input, try again");
}
This works fine for input like "/" or "-" but when you input "54.32" then it will read until the ".", the read count of scanf will be 1 and 54 will be stored in g. Is there a way to check if the input consists solely of a single integer followed by nothing but a newline character?
I would like to know if there exists a solution without using fgets or any other IO function?
to check solely of a single integer followed by nothing but a newline character
Use "%n" to record number of characters scanned, if it gets that far.
int n = 0;
scanf("%d*1[\n]%n", &g, &n);
if (n > 0) puts("input consists solely of a single integer followed by a newline");
If the result is not as hoped, additional code needed to cope with the errant input.
I recommend using fgets() to solve the larger problem.
Edit because I misunderstood the question: what about this?
#include <stdio.h>
int main() {
int n;
char c;
scanf("%d", &n);
scanf(" %c", &c) ? printf("incorrect input, try again\n") : printf("%d\n", n);
return 0;
}
You can use the assignment-suppressing format operator to extract everything (anything) after the integer, and the number-of-characters-read format specifier to see whether that matched anything, without having to store it anywhere.
See your documentation.
Eg,
int g, gchars, xchars;
scanf("%d%n%*s%n", &g, &gchars, &xchars);
if (xchars > gchars)
printf("%d extra characters discarded after integer %d\n", xchars-gchars, g);

Is it possible to get two inputs of different datatypes in one scanf() in c?

I want to get the command as input like
<char><number><number>
so is it possible to get it using one scanf() function in c ?
int i,j;
char c;
scanf("%c%d%d",&c, &i, &j);
I don't think that will work because the compiler will consider that as something together rather than one character, and two integers but to take the input in this format i.e. to make the compiler understand that you can take the entire line as a string and then parse the string to extract the character and the integers
char a[1000],c; int x,y;
scanf("%s",a);
c = a[0];
x = a[1] - '0';
y = a[2] - '0';
Also, #BLUEPIXY gave even better solution to your problem!
You can get more than 1 input in 1 scanf as the following:
char ch, string[100];
int number;
printf("--char--/--number--/--string--");
scanf(" %c%d %s",&ch,&number,&string[0]); // -> be careful about the whitespaces
printf("%c\n",ch);
printf("%d\n",number);
printf("%s\n",string);
You dont need to use spaces or \n to enter your input.

How to limit the input on a 2D array so it won't blow up?

I have a small program, where i say the number of lines and columns of a array I want to input, then input info to fill that array with data. What it does next it's not important so ill just omit that part of the code and put (...) in it.
int main (){
int nl, nc,i,j,z,n;
scanf ("%d %d\n", &nl,&nc);
char matrix [nl] [nc];
for (i=0;i<nl;i++)
for (j=0;j<nc;j++)
scanf(" %c",&matrix[i][j]);
scanf("%d",&n);
int s[n*2];
for (z=0;z<n*2;z++)
scanf("%d",&s[z]);
int y=0;
char s2[n];
for (z=0;z<n*2;z+=2){
s2[y]=matrix [(s[z])-1][(s[z+1])-1];
y++;
}
for (z=0;z<n;z++)
printf ("%c", s2[z]);
return 0;
}
My problem is, that it this blows up if input more chars than I should. For example if my input is:
2 3
ABC
DEF
This works just fine.
But if I put:
2 3
ABC
DEFF
It give me a segmentation fold and stops the program. Keep in mind that I have a space before the "%c" in scanf so it's ignoring the "\n" and spaces I put in the input.
What can I do to stop that extra chars in the array from blowing up?
scanf("%d",&n);
int s[n*2];
This code tries to scan and convert whatever is left in the input after reading the matrix. If the input is not numeric, as will be the case if you enter more letters than the matrix should contain, the conversion will fail and n will remain uninitialized. Then int s[n*2]; is undefined because n is indeterminate.
If you want to ignore some characters in the input, you need to do so explicitly. You also better check return values of all functions that take user input, and verify that the values read are sensible.
Ok i figured out that the problem with it was input going to the buffer. To solve this i cleared the buffer before the next input using:
while (getchar() != '\n');
Your problem is filling the array over that size.
You get your input character by character and if you enter character more than your array size the program will stopped or has been logical error,
So you can use getche() and check the array constraint.
You can edit your code as follow:
int main (){
int nl, nc,i,j;
scanf ("%d %d\n", &nl,&nc);
char matrix [nl] [nc];
for (i=0;i<nl;i++)
for (j=0;j<nc;j++)
matrix[i][j]=getche();
(...)
return 0;
}
Use %s instead of %c and remove the inner loop. So the code will be something like this:
for(i=0; i<nl; i++)
{
scanf("%s", &matrix[i]);
}

Printing partial char arrays...with a twist

So I know there are a lot of questions about printing only segments of char arrays in C and I have read them and though my question is similar in nature, there is a small twist to mine. Given my code below, how do I only print out the first four characters of my fmt array? I am not allowed to alter fmt so therefore I must use VAL to specify that I just want to print the value, the new line, and one space.
#define VAL 4
int main() {
char fmt[10] = "%d\n ";
int value = 1;
printf(fmt, value);
}
EDIT:
This is just a fraction of my code because I felt this was all that was necessary. If more is needed I will provide the rest of my code.
EDIT2:
Restrictions:
No new variables & must use VAL to specify how much of the fmt array to be printed.
EDIT3 (FULL QUESTION):
Fill in the missing part of the program, without adding any variable declarations. Ask the user to choose how s/he wants to print the entered integer value. (Look up the integer format specifiers for printf if you don't know them all.) Using the indicated format specifier letter print the integer that was entered earlier, followed by a return, and then reprompt for another format letter (though not for a new integer).
Getting under the complexity limit is a major part of the challenge. Be flexible about which type of loop you choose, and how you read in the format-specifier character. Also, note that scanf skips whitespace when reading a character, if there is a blank before the %c in the format string. And, there is an important use for that VAL define, involving getting rid of spurious blanks in the output. And finally, don't even think about doing this with a big switch or if-else block.
#include <stdio.h>
#define VAL 4 // You might want this
int main() {
char fmt[10] = "%d\n "; // Quickly initializes fmt array
int value;
printf("Enter an integer: ");
scanf("%d", &value);
//from here below is my code, above code is pre-provided
printf("Enter a format specifier (x, X, c, d, i, o, or q to quit): ");
scanf(" %c", &fmt[1]);
while (fmt[1] != 'q') {
printf("%4s", fmt, value);
printf("Enter a format specifier (x, X, c, d, i, o, or q to quit): ");
scanf(" %c", &fmt[1]);
}
}
how do I only print out the first four characters of my fmt array
How about:
printf("%4s", fmt);
It doesn't work because I need the variable value to tell the %d in
fmt what to print out
Options:
Print to a separate string (snprintf) using a length of 4
Process your number until it contains the appropriate number of digits and then print
Adding to cnicutars very good answer, I'd just like to point out that if the array isn't const, you can alter it:
char saved = fmt[4];
fmt[4] = '\0';
printf (fmt, value);
fmt[4] = saved;
Edit
As I specified in my original question, the array cannot be altered.
Yes, well... I misread and thought the original const format string cannot be altered. Nevertheless, I think this tidbid of information can be useful to someone else.
After reading value from input then print could be:
printf("%.*s", VAL, fmt, value);

segmentation fault in C programming

I started learning C programming and in this program I am trying to get user input and then a line at a time and decide if it contains non-int characters. I've been trying this method:
scanf("%d", &n);
if (isalpha(n))
{
i = -1;
}
I googled a bit and learned the function isalpha is good way to do it. However, I'm getting a segmentation fault every time I test the fragment above with non-int characters (letters for example). Any suggestion would be appreciated.
The %d format specifier forces scanf() to only accept strings of digits. Given anything else, it will fail and leave n unfilled (and assuming you didn't initialize n before, it will be filled with garbage).
The crux of the problem is that isalpha() expects a value between 0 and 255, and has an assertion to enforce it. At least on my VC++ compiler, it causes a crash with an access violation when given an invalid value (in non-debug mode).
To solve this you just have to switch to a %c format specifier. Converting n to a char would also be advisable as that makes your intent of reading a single character clearer.
EDIT: Given your clarifications in the comments, you can leave everything as is and simply check the return value of scanf() instead of going the isalpha() route. It returns the number of values read successfully, so when it encounters a non-integer or end of file, it will return 0. E.g.:
int main() {
int n;
while (scanf("%d", &n)) {
printf("Got int: %d\n", n);
}
}
I have no idea why you're getting a seg-fault. I'd have to see more of your program.
But using "%d" for scanf will only accept integer values and you'll get "0" for n that isn't an integer and therefore isalpha(n) will always be false and i will never be set to -1.
Perhaps you aren't initializing i and therefore it is never set. If you are referencing it later, that's probably the source of your seg-fault.
Use scanf("%c", &n), like this:
int main(char** argc, int argv) {
char n = 0;
int i = 0;
scanf("%c", &n);
if (isalpha(n)) {
i = -1;
}
printf("you typed %c, i=%d", n, i);
}
Make sure you have a character buffer to store the value in. Scan it as a string, and then use isalpha():
char buffer[32];
sscanf("%32s", buffer);
// loop and check characters...
if(isalpha(buffer[i])) ....
Note the use of %32s, this is to prevent buffer overflows (32 == size of buffer)
Given that n is an integer, we can diagnose that you are reading a value into n which is not in the range 0..255 plus EOF (normally -1), so that the code for isalpha(n) is doing something like:
(_magic_array[n]&WEIRD_BITMASK)
and the value of n is causing it to access memory out of control, hence the segmentation fault.
Since scanf():
Returns the number of successful conversions, and
Stops when there is a non-integer character (not a digit or white space or sign) in the input stream,
you can use:
#include <stdio.h>
int main(void)
{
char n = 0;
while (scanf("%c", &n) == 1)
printf("you typed %d\n", n);
return 0;
}

Resources