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.
Related
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.
I wrote a program that scans an unknown amount of integers into an array but when I run it, it print the last value it has gotten an infinite amount of times.
For example for the input: 1 2 3 4 5
The output would be 55555555555555555555555...
Why does this happen and how can I fix that?
My goal here is to create a array, for an instance {1, 2, 3, 4, 5} and then print what it scanned into the array, ONLY ONCE...
int *pSet = (int*) malloc(sizeof(int)); int i; int c;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
scanf("%d", &c);
pSet[0] = c;
printf("%d ", c);
for(i = 1; c != EOF; i++) {
pSet = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSet == NULL) {
return FAIL;
}
scanf("%d", &c);
pSet[i] = c;
printf("%d ", c);
}
free(pSet);
Why does this happen (?) (print ... an infinite amount of times.)
Look at the loop terminating conditions c != EOF.
int c;
scanf("%d", &c);
for(i = 1; c != EOF; i++) { // Not good code
scanf("%d", &c);
}
EOF is some negative value, often -1. scanf("%d", &c) attempts to read user input and convert to an int. scanf() returns a 1,0,EOF depending on if it 1) succeeded, 2) failed to find numeric text or 3) end-of-file or input error occurred. Unfortunately code does not use that return value. Instead code used the number read, c and checked if that number read was the same as EOF.
how can I fix that?
Only loop when the return value of scanf() is as expected (1).
for(i = 1; scanf("%d", &c) == 1; i++) {
...
}
Putting this together with some other ideas
#include <stdio.h>
#include <stdio.h>
int main(void) {
printf("Please enter a stream of numbers to make a set out of them:\n");
int *pSet = NULL; // Start with no allocation
size_t i = 0;
int c;
for (i = 0; scanf("%d", &c) == 1; i++) {
// +--------------------------- No cast needed.
// v v----------v Use sizeof de-referenced pointer
void *p = realloc(pSet, sizeof *pSet * (i + 1));
if (p == NULL) {
free(pSet);
return EXIT_FAILURE;
}
pSet = p;
pSet[i] = c;
}
for (size_t j = 0; j < i; j++) {
printf("%d ", pSet[j]);
}
free(pSet);
return 0;
}
There are a number of problems.
1) Terminate the loop when scanf fails instead of using EOF. Do that by checking that the return value is 1 (i.e. the number of input items
successfully matched)
2) Don't allocate memory until it's needed
3) Never do realloc directly into the target pointer - always use a temp variable.
Fixing this your code could be:
#include <stdio.h>
int main(void) {
int *pSet = NULL;
printf("Please enter a stream of numbers to make a set out of them: ");
printf("\n");
int i = 0;
int c;
while (1) {
if (scanf("%d", &c) != 1)
{
printf("Terminating input loop\n");
break;
}
int* tmp = realloc(pSet, sizeof(int)*(i+1));
if(tmp == NULL) {
printf("oh dear...\n");
break;
}
pSet = tmp;
pSet[i++] = c;
printf("%d ", c);
}
for (int j=0; j < i; ++j) printf("%d\n", pSet[j]);
free(pSet);
return 0;
}
Input:
1 2 3 4 5 6 7 stop
Output:
Please enter a stream of numbers to make a set out of them:
1 2 3 4 5 6 7
Terminating input loop
1
2
3
4
5
6
7
You should stop your loop when scanf fails. According to the manual:
On success, [scanf] return[s] the number of input items successfully matched and assigned; this can be fewer than provided for, or even zero, in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs. [...]
So you can turn your for loop into a while one.
#include <stdio.h>
#include <stdlib.h>
#define FAIL 0
int main() {
int *pSet = (int*) malloc(sizeof(int));
int c;
int i=0;
printf("Please enter a stream of numbers to make a set out of them: ");
while(scanf("%d", &c) == 1) {
pSet[i] = c;
pSetNew = (int*) realloc(pSet, sizeof(int)*(i+1));
if(pSetNew == NULL) {
free(pSet);
return FAIL;
} else {
pSet = pSetNew;
}
printf("%d ", c);
i++;
}
free(pSet);
}
But if you want a more robust piece of code, I suggest you to retrieve the answer as a string (NULL-terminated array of char), and then parse it with dedicated functions like strtol which let you check if the whole string is a valid entry, and not only the first characters.
Note: HengLi fixed a potential memory leak in the code sample above
I am trying to write an application in C and I have a problem: I have some unwanted chars in my string2 array in the code part below:
#include <stdio.h>
#include <string.h>
#define max_len 100
int main() {
char string1[max_len], string2[max_len], string3[max_len], temp[max_len];
int m, n, i, j, k, min_str_len;
puts("Enter your first word: ");
gets(string1);
puts("Enter your second word: ");
gets(string2);
m = strlen(string1);
n = strlen(string2);
min_str_len = ((m < n) ? m : n);
for (i = 0; i <= m; i++) {
for (j = 0; j <= n; j++) {
for (k = 0; k <= min_str_len; k++) {
if (string1[i] == string2[j]) {
//printf("%s",string2[j]);
temp[k] = string2[j];
break;
}
...
}
}
}
So you see here a part of my code. I am assigning "placozoa" as string1, and "placement" as string2. Please see the line: //printf("%s",string2[j]); When I make this line active, I see:
I did not understand why [] and ' characters are included in string2, I was just expecting to see "plac" there in the output.. The weird thing is, I am printing string2 array right after getting from the user (under gets(string2); line), and I see it is "placement" there.
What is happening in the middle, where is my mistake?
In your print statement, printf("%s",string2[j]); use %c instead of %s,
Because %s always try to convert the printing item to string. And to do that, your compiler has added a null char at the end of it.
So what actually happening right now,
when j == 0, string2[j] is equal to 'p' as a single charcter, but as string it becomes "p\0" where \0 is the null character which means the end of a string.
So, I think, just printing as a single character using %c (character) will solve the problem.
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;
}
My task is read two strings of digits and save them in different arrays.
I decided to use scanf function, but program can read only first string.
This is my bad-code.
int main()
{
int firstArray[50], secondArray[50], i, j;
/* fill an array with 0 */
for(i=0; i<50; ++i)
{
firstArray[i]=secondArray[i]=0;
}
i=j=0;
while((scanf("%d", &firstArray[i]))== 1) { ++i; }
while((scanf("%d", &secondArray[j]))== 1) { ++j; }
/* Print this. */
for(i = 0; i < 20; ++i)
{
printf("%d ", firstArray[i]);
}
putchar('\n');
for(j = 0; j < 20; ++j)
{
printf("%d ", secondArray[j]);
}
return 0;
}
I just don't understand how scanf function works. Can someone please explain?
scanf ignores blank characters (including new line). Thus your scan will read entire input into firstArray if you have no "non blank" separator.
If file/data has ; at end of first line it will stop the read into firstArray there, and never read anything into secondArray - as you never consume the ;.
/* This will never be 1 as ; is blocking */
while((scanf("%d", &secondArray[i])) == 1) {
So: if you separate with i.e. ; you will have to read / check for this before you read into secondArray.
You could also add something like:
char c;
/* this can be done more tidy, but only as concept */
while((scanf("%d", &firstArray[i])) == 1 && i < max) {
++i;
if ((c = getchar()) == '\n' || c == ';')
break;
}
Also instead of initializing array to 0 by loop you can say:
int firstArray[50] = {0}; /* This set every item to 0 */
Also take notice to ensure you do not go over your 50 limit.
You say strings of digits and you read %d. The format scans the input for the longest sequence representing an integer (signed) value. Two "digit strings" are consumed by the first while loop.
EDIT Instead of "strings of digits" you should say "strings of integers". In this case it is a little bit more subtle since the first while can consume all the integers, unless they are separated by something that is not a possible integer (e.g. a ;).
So, to make the following to work, you must separate the two "lines" with something that can't be parsed as integer and which is not considered "white character". Not the better solution, but one the possible.
#include <stdio.h>
#include <ctype.h>
int main()
{
int firstArray[50] = {0};
int secondArray[50] = {0};
int i, j, l1, l2;
int tmp;
i = j = 0;
// read integers, but not more than size of array
while( scanf("%d", &firstArray[i]) == 1 && i < sizeof(firstArray) ) {
++i;
}
// consume non digits
for(tmp = getchar(); tmp != EOF && !isdigit(tmp); tmp = getchar());
// on EOF you should exit and stop processing;
// we read one more char, push it back if it was a digit
if (isdigit(tmp)) ungetc(tmp, stdin);
while( scanf("%d", &secondArray[j]) == 1 && j < sizeof(secondArray) ) {
++j;
}
l1 = i; // preserve how many ints were read
l2 = j;
/* Print this. */
for(i = 0; i < l1; ++i)
{
printf("%d ", firstArray[i]);
}
putchar('\n');
for(j=0; j < l2; ++j)
{
printf("%d ", secondArray[j]);
}
return 0;
}
EDIT A solution that maybe fits your need better is to read the lines (one per time) into a buffer and sscanf the buffer.
You cannot use scanf to do that.
Read the documentation.
Observations:
with scanf if you enter a digit your loop runs forever
there is no check on size 50 limit of your arrays
if you press return then it ignores that line because does not match your pattern
if you enter a letter the pattern does not match and loop breaks
So use some other function, maybe gets, atoi or strtol. And remember to check the size 50 limit of your arrays.
Actually, there is one special point in C's arrays.
Though you declare an array's size. say int arr[5]; You can store values beyond the size of 5. It doesn't show any error but leads to undefined behavior (Might overwrite other variables).
Please Refer this question: Array size less than the no. of elements stored in it
In you case, that was your problem. The compiler had never passed beyond the first while statements. Thus, you didn't get any output. In fact, it didn't even compile the whole code yet!
while((scanf("%d", &firstArray[i]))== 1) { ++i; }
So, you could write this while statement like this:
while( scanf("%d", &firstArray[i]) ==1 && i<50 )
i++;
or else:
while(i<50 )
{
scanf("%d", &firstArray[i]);
i++;
}
or else:
for (i=0; i<50; i++)
scanf("%d", &firstArray[i]);