scanf is getting skipped, showing segmentation fault [duplicate] - c

This question already has answers here:
scanf() leaves the newline character in the buffer
(7 answers)
Closed 2 years ago.
This code says segmentation fault cause the program's scanf isn't working. I used a debugger to find out this. The scanf(num) is skipped. And thus the segmentation fault. Can somebody tell why the scanf is being skipped? I used [^\n] so that scanf can read string with spaces. Help.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
int a, b;
scanf("%d %d", &a, &b);
int sumr, maxr;
int sumc, maxc;
int white[b + 1];
white[0] = -1;
int ele[b][a];
for (int opl = 0; opl < a; opl++)
{
for (int pl = 0; pl < b; pl++)
{
ele[pl][opl] = 0;
}
}
char num[100000];
int c = -1;
c:
c++;
scanf("%[^\n]%*c", num);
int hu = 0;
int len = strlen(num);
white[b] = len;
for (int ji = 0; ji < len; ji++)
{
if (isspace(num[ji]))
{
white[hu] = ji;
hu++;
}
}
for (int ft = 0; ft < b; ft++)
{
int lopl = 1;
for (int koi = white[ft + 1] - 1; koi > white[ft]; koi--)
{
ele[ft][c] += lopl * (num[koi] - '0');
lopl = lopl * 10;
}
}
if (a > c)
goto c;
}

scanf("%[^\n]%*c", num);
As a first step. you should always check the return value of functions that can adveresely affect your program. In other words, something like:
if (scanf("%d %d", &a, &b) != 2) { handleOneProblem(); }
if (scanf("%[^\n]%*c", num) < 1) { handleAnother(); }
If that second one fails, then num will be left containing whatever arbitrary data it contained before the call, and you probably don't want to then use it as if it contains a valid string.
On top of that, you should be aware that some, but not all, scanf format specifiers will gobble up white space before attempting to read the data. For example, %d will first skip over whitespace and then attempt to read an integer. However, format specifiers such as [ and c will not.
And none of them will gobble up whitespace after the field has been read for the format specifier. That means, if you want that done, you need to do it yourself, with a set of functions like:
#include <stdio.h>
int gobbleLineFile(FILE *inFile) {
int ch;
while ((ch = fgetc(inFile)) != '\n' && ch != EOF) {}
return ch;
}
int gobbleLineStdIn(void) { return gobbleLineFile(stdin); }
As an aside, a lot of problems with scanf are caused by mixing those format specifiers that skip white-space, with those that don't. You can code around that as per above suggestion but, if you're expecting the user to give line-based input, it's often better to do everything as line-based, then use sscanf to break apart the lines.
A fairly decent line-based input routine can be found here.

You have to catch the '\n' that was left from the first scanf.
Either change it to: scanf("%d %d\n", &a, &b);
or put a getchar(); right after it.
Because the next reading: scanf("%[^\n]%*c", num); will read until the next '\n', which is the first thing left on the buffer.

Related

How to make "overloaded" scanf in C?

Friends how can I make Scanf to take 1 or 2 or 3 numbers depending on input data I give?
sample data 1: "1 2 5"
sample data 2: "1 4"
sample data 3: "4"
if(scanf("%lf",&a)==1 )
{
printf("1 input num\n");
}
else if(scanf(" %lf %lf",&a, &b)==2 )
{
printf("2 input num\n");
}
else if(scanf("%lf %lf %lf",&a, &b, &c)==3 )
{
printf("3 input num\n");
}else
{
printf("Error message.\n");
return 1;
}
You might consider this an answer:
int InputNums=0;
InputNums = scanf("%lf %lf %lf",&a, &b, &c);
if(InputNums!=0)
printf("%d input num\n");
else
printf("Error message.\n");
It works by NOT eating one number and then trying whether instead more numbers could have been read, like your shown code does.
Instead try to read three numbers and then let scanf() tell you how many worked.
But actually I am with the commenters. If you do not have guaranteed syntax in your input (which scanf() is for) then use something else.
This is nicely describing which alternative in which situation AND how to get scanf to work in the same situation:
http://sekrit.de/webdocs/c/beginners-guide-away-from-scanf.html
Scanf already does this for you, and indeed you used the same scanf function with a variable number of arguments. You can look here: How do vararg work in C?
However you don't need to overload scanf, but rather pass to it a string telling what you need to scan. You can do this dynamically by changing the string at runtime.
The code to try is the following:
#include <stdio.h>
int main()
{
char one[] = "%d";
char two[] = "%d%d";
int o1;
int t1,t2;
scanf(one,&o1);
scanf(two,&t1,&t2);
printf("%d %d %d",o1,t1,t2);
return 0;
}
If you must use scanf() ....
"%lf" is a problem as it consumes leading white-space including '\n', so we lost where a line of input might have ended.
Instead first look for leading white-space and see if an '\n' occurs.
#define N 3
double a[N];
count = 0;
while (count < N) {
// Consume leading white-spaces except \n
unsigned char ch = 0;
while (scanf("%c", &ch) == 1 && isspace(ch) && ch != '\n') {
;
}
if (ch == '\n') {
break;
}
// put it back into stdin
ungetc(ch, stdin);
if (scanf("%lf", &a[count]) != 1)) {
break; // EOF or non-numeric text
}
count++;
}
printf("%d values read\n", count);
for (int i=0; i<count; i++) {
printf("%g\n", a[i]);
}
Alterantive to consume various multiple leading whitespaces that only uses scanf() with no ungetc():
// Consume the usual white spaces except \n
scanf("%*[ \t\r\f\v]");
char eol[2];
if (scanf("%1[\n]", eol) == 1) {
break;
}
If the line contains more than N numbers or non-numeric text, some more code needed to report and handle that.
The best solution to problems with scanf and fscanf is usually to use something other than scanf or fscanf. These are remarkably powerful functions, really, but also very difficult to use successfully to handle non-uniform data, including not only variable data but data that may be erronious. They also have numerous quirks and gotchas that, though well documented, regularly trip people up.
Although sscanf() shares many of the characteristics of the other two, it turns out often to be easier to work with in practice. In particular, combining fgets() to read one line at a time with sscanf() to scan the contents of the resulting line is often a convenient workaround for line-based inputs.
For example, if the question is about reading one, two, or three inputs appearing on the same line, then one might approach it this way:
char line[1024]; // 1024 may be overkill, but see below
if (fgets(line, sizeof line, stdin) != NULL) { // else I/O error or end-of-file
double a, b, c;
int n = sscanf(line, "%lf%lf%lf", &a, &b, &c);
if (n < 0) {
puts("Empty or invalid line");
} else {
printf("%d input num\n", n);
}
}
Beware, however, that the above may behave surprisingly if any input line is longer than 1023 characters. It is possible to deal with that, but more complicated code is required.
here is an example of using fgets, strtok and atof to achieve same:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char input[256];
double inputsf[256];
while(1) {
printf(">>> "); fflush(stdout);
char *s = fgets(input, 255, stdin);
if (!s)
break;
int count = 0;
char *t;
while (t = strtok(s, " \n")) {
s = NULL;
inputsf[count++] = atof(t);
}
printf("Found %d inputs\n", count);
for (int i = 0; i < count; i++)
printf(" %lf\n", inputsf[i]);
if (count == 0)
break;
}
return 0;
}
Bases on the #chux-ReinstateMonica comment, here is a piece of code which uses strtod. It skips leading spaces, but has an issue with the tailing spaces at the end of the string. So, some extra checking is needed there, which could be used for error checking as well. The following loop can replace the strtok loop from above.
while(*s) {
char *e;
double val = strtod(s, &e);
if (e == s)
break; // not possible to parse, break the loop
inputsf[count++] = val;
s = e;
}
You can solve your problem using those line of code
#include <stdio.h>
int main(){
int a[100];
int n;
printf("How many data you want to input: ");
scanf("%d", &n);
printf("Sample %d data Input: ", n);
for (int i=0; i <n; i++) {
scanf("%d", &a[i]);
}
printf("Sample data %d: ", n);
for (int i=0; i <n; i++) {
printf("%d ", a[i]);
}
if(n == 1){
printf("\n 1 input num\n");
}else if(n==2){
printf("2 input num\n");
}else if(n==3){
printf("3 input num\n");
}else{
printf("Error");
}
return 0;
}
if you want to take multiple input in single line use this line
int arr[100];
scanf ("%lf %lf %lf", &arr[0], &arr[1], &arr[2]);

Why scanf cannot read my input?

I would like use scanf() to read the following table:
Q 1 3
U 2 6
Q 2 5
U 4 8
This is my code:
#include <stdio.h>
#include <stdlib.h>
void main() {
int *a;
int i, j;
a = (int *) malloc(4 * 3 *sizeof(int));
printf("input:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < 3; j++) {
scanf("%d", a + 3 * i + j);
}
}
printf("output:\n");
for (i = 0; i < 4; i++) {
for (j = 0; j < 3; j++) {
printf("%d ", a[3*i+j]);
}
printf("\n");
}
}
However, when I input the first line Q 1 3, this program end. I don't know why?
This happens because you provided a non-numeric input to your program that wants to read a number with %d. Since Q is not a number, scanf fails.
However, your program is not paying attention to the return value of scanf, and keeps calling it in the failed state. The program thinks that it is getting some data, while in fact it does not.
To fix this, change the code to pass %c or %s when it reads the non-numeric character, check the return value of scanf, and get rid of invalid input when scanf fails.
When you call scanf, it returns how many values corresponding to % specifiers it has provided. Here is how to check the return value of scanf:
if (scanf("%d", a + 3 * i + j) == 1) {
... // The input is valid
} else {
fscanf(f, "%*[^\n]"); // Ignore to end of line
}
It's because the letter Q is not a number, so scanf will fail and leave the input buffer untouched. So the next iteration scanf will see the same Q and again fail, and so on and on and on...
That will mean nothing is actually read into the memory you allocate, and you print out the uninitialized memory, leading to undefined behavior.
One possible way to solve your problem might be to read lines instead (using e.g. fgets), and then use sscanf to parse the whole line in one go. Perhaps something like
for (i = 0; i < 4; i++) {
char buffer[64];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {
char c; // The character
int a, b; // The integer values
sscanf(buffer, "%c %d %d", &c, &a, &b);
a[3 * i + 0] = c;
a[3 * i + 1] = a;
a[3 * i + 2] = b;
}
}
I also recommend you actually initialize the memory you allocate, especially if you're not going to use parts of it but still print it out.
Either use scanf() with int variable with proper ASCII value or use scanf() with char variable for character but print with %c in both cases. ASCII code for Q is 81 and for U it is 85.

Can you lend me a hand with this word counting code?

This code don't count words properly. I don't know if it is wrong on the for or what. Need help.
#include <stdio.h>
#include <stdlib.h>
int count_p(char sentence[100]) {
int i, m = 1;
for (i = 0 ; i < 100 ; i++) {
if (sentence[i] == ' ') {
m += 1;
}
}
return(m);
}
void main() {
char s[100];
int p;
printf("Sentence here: ");
scanf("%s", &s[50]);
p = count_p(sentence);
printf("Words: %d", p);
printf("\n");
}
The %s in scanf stops reading when it found a whitespace. Therefore, ' ' won't appear in s unless it was there as indeterminate value in uninitialized variable.
You can use fgets to read a whole line.
Here is a fixed code that also checks for end of the string.
#include <stdio.h>
#include <stdlib.h>
int count_p(char sentence[100]) {
int i, m = 1;
for (i = 0 ; i < 100 && sentence[i] != '\0'; i++) {
if (sentence[i] == ' ') {
m += 1;
}
}
return(m);
}
int main(void) {
char s[100];
int p;
printf("Sentence here: ");
fgets(s, sizeof(s), stdin);
p = count_p(s);
printf("Words: %d", p);
printf("\n");
return 0;
}
scanf("%s", &s[50]);
Not a correct way to take input and writing at index which is out of bound. Do this instead -
scanf("%99[^\n]", s); // this will read 99 characters and until '\n' is encountered
In main you function call is incorrect -
p = count_p(sentence); // sentence is not declares in main
Call like this -
p = count_p(s); // pass s instead of sentence to function
Also in function count_p change ccondition in for loop as -
size_t i;
size_t len=strlen(s);
for (i = 0 ; i < len ; i++)
You see &s[50] means that you pass a pointer to the 51-th element of s, you then try to access s from the beginning but, the first 50 characters in s were not yet initialized, this leads to undefined behavior.
Also, your loop from 0 to 99 will have the same issue since you might input a string of less than 100 characters, in that case you would be accessing uninitialized data too.
You can fix your program by changing this
scanf("%s", &s[50]);
to
scanf("%99s", s);
and then
for (i = 0 ; i < 100 ; i++) {
to
for (i = 0 ; s[i] != '\0' ; i++) {
because scanf() will append a '\0' to make the array a valid c string, that's also the reason for the "%99s".
Another problem is that, if you want white space characters not to make scanf() stop reading, you need a different specifier, because "%s" stops at the first white space character, this is a suggestion
scanf("%99[^\n]", s);
Or you can do as #MikeCAT suggested and go with fgets(). But be careful with the trailing '\n' in case of fgets().
And finally, altough highly unlikely in this situation, scanf() might fail. To indicate success it returns the number of specifiers actually matched, thus it might indicate partial success too. It's fairly common to see the return value of scanf() ignored, and it's very bad when you have a "%d" specifier for example because then the correspoinding parameter might be accessed before initializing it.
The statement scanf("%s", &s[50]); is in correct in your situation.Since you want to enter a sentence separated by spaces,the correct way of doing it is :
scanf(" %99[^\n]s",sentence);
That will prevent buffer overflow and allow space between words.Also your program does not seem to count words correctly if the sentence has consecutive whitespaces.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int count_p(char *sentence);
void main()
{
char sentence[100];
printf("Sentence here: ");
scanf(" %99[^\n]s",sentence);
int p = count_p(sentence);
printf("Words: %d", p);
printf("\n");
}
int count_p(char *sentence)
{
int len = strlen(sentence);
int x = 0 , wordCount = 0;
for( int n = 0 ; n < len ; n++ )
{
x++;
if( sentence[n] == ' ' )
x = 0;
if( x == 1 )
wordCount++;
}
return wordCount;
}

Which format should I use: scanf \string,string,int,int/?

I have data in the following format \a,b,c,d/ where a,b are strings of letters and numbers; c, d are integers.
I tried using format \%s,%s,%d,%d/ format to scan it, but that causes a,b,c,d/ to be scanf'ed into the first string instead of only a.
Question:
Is there something I could type in the format in order to achieve desired result?
You can use the following format string to use commas as delimiters :
"\\%[^,],%[^,],%d,%d/"
The idea is to tell scanf to read anything that isn't a comma for each string, then read the delimiting comma and continue.
Here is a (bad and unsafe!) example:
char a[100], b[100];
int c=0, d=0;
scanf("\\%[^','],%[^','],%d,%d/", a, b, &c, &d);
printf("%s, %s, %d, %d\n", a, b, c, d);
In real code, you'll want to write something safer. You can for example use fgets to read a full line of input then reuse the same format string with sscanf to parse it.
Read carefully the documentation of fscanf(3).
You might try something like
char str1[80];
char str2[80];
memset (str1, 0, sizeof(str1));
memset (str2, 0, sizeof(str2));
int n3 = 0, n4 = 0;
int pos = -1;
if (scanf ("\\ %79[A-Za-z0-9], %79[A-Za-z0-9], %d, %d /%n",
str1, str2, &n3, &n4, &pos) >= 4
&& pos > 0) {
// be happy with your input
}
else {
// input failure
}
That won't work if you have a wider notion of letters, like French é or Russian Ы ; both are single letters existing in UTF-8 but represented in several bytes.
I added some spaces (mostly for readability) in the format string (but scanf is often skipping spaces anyway, e.g. for %d). If you don't accept spaces -like an input line such as \AB3T, C54x, 234, 65/ , read each line with getline(3) or fgets(3) and parse it manually (perhaps with the help of sscanf and strtol ...). Notice that %d is skipping spaces! I also am clearing the variables to get more deterministic behavior. Notice that %n gives you the amount of read characters (actually, bytes!) and that scanf returns the number of scanned items.
My straightforward solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char a[10010];
gets(a);
int l = strlen(a);
char storded_first[10010], storded_second[10010];
char for_int_c[10010], for_int_d[10010];
int c,d;
char first_symbol, last_symbol;
int i;
int cnt = 0;
int j=0;
for(i=0; i<l; i++)
{
if(a[i]=='\\')
first_symbol = a[i];
else if(a[i]=='/')
last_symbol = a[i];
else if(a[i]==',')
{
cnt++;
j=0;
}
else if(cnt==0)
{
storded_first[j]=a[i];
j++;
}
else if(cnt==1)
{
storded_second[j]=a[i];
j++;
}
else if(cnt==2)
{
for_int_c[j]=a[i];
j++;
}
else if(cnt==3)
{
for_int_d[j]=a[i];
j++;
}
}
c = atoi(for_int_c);
d = atoi(for_int_d);
printf("%c%s, %s, %d, %d%c\n",first_symbol, storded_first, storded_second, c, d, last_symbol);
return 0;
}

How to read from input until newline is found using scanf()?

I was asked to do a work in C when I'm supposed to read from input until there's a space and then until the user presses enter.
If I do this:
scanf("%2000s %2000s", a, b);
It will follow the 1st rule but not the 2nd.
If I write:
I am smart
What I get is equivalent to:
a = "I";
b = "am";
But It should be:
a = "I";
b = "am smart";
I already tried:
scanf("%2000s %2000[^\n]\n", a, b);
and
scanf("%2000s %2000[^\0]\0", a, b);
In the 1st one, it waits for the user to press Ctrl+D (to send EOF) and that's not what I want.
In the 2nd one, it won't compile. According to the compiler:
warning: no closing ‘]’ for ‘%[’ format
Any good way to solve this?
scanf (and cousins) have one slightly strange characteristic: white space in (most placed in) the format string matches an arbitrary amount of white space in the input. As it happens, at least in the default "C" locale, a new-line is classified as white space.
This means the trailing '\n' is trying to match not only a new-line, but any succeeding white-space as well. It won't be considered matched until you signal the end of the input, or else enter some non-white space character.
One way to deal with that is something like this:
scanf("%2000s %2000[^\n]%c", a, b, &c);
if (c=='\n')
// we read the whole line
else
// the rest of the line was more than 2000 characters long. `c` contains a
// character from the input, and there's potentially more after that as well.
Depending on the situation, you might also want to check the return value from scanf, which tells you the number of conversions that were successful. In this case, you'd be looking for 3 to indicate that all the conversions were successful.
scanf("%2000s %2000[^\n]", a, b);
use getchar and a while that look like this
while(x = getchar())
{
if(x == '\n'||x == '\0')
do what you need when space or return is detected
else
mystring.append(x)
}
Sorry if I wrote a pseudo-code but I don't work with C language from a while.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
int main(void)
{
int i = 0;
char *a = (char *) malloc(sizeof(char) * 1024);
while (1) {
scanf("%c", &a[i]);
if (a[i] == '\n') {
break;
}
else {
i++;
}
}
a[i] = '\0';
i = 0;
printf("\n");
while (a[i] != '\0') {
printf("%c", a[i]);
i++;
}
free(a);
getch();
return 0;
}
I am too late, but you can try this approach as well.
#include <stdio.h>
#include <stdlib.h>
int main() {
int i=0, j=0, arr[100];
char temp;
while(scanf("%d%c", &arr[i], &temp)){
i++;
if(temp=='\n'){
break;
}
}
for(j=0; j<i; j++) {
printf("%d ", arr[j]);
}
return 0;
}
#include <stdio.h>
int main()
{
char a[5],b[10];
scanf("%2000s %2000[^\n]s",a,b);
printf("a=%s b=%s",a,b);
}
Just write s in place of \n :)
//increase char array size if u want take more no. of characters.
#include <stdio.h>
int main()
{
char s[10],s1[10];
scanf("\n");//imp for below statement to work
scanf("%[^\n]%c",s);//to take input till the you click enter
scanf("%s",s1);//to take input till a space
printf("%s",s);
printf("%s",s1);
return 0;
}

Resources