#include <stdio.h>
#include <stdlib.h>
int main () {
int firstDigit;
char *firstNumber = 0;
char operator;
int secondDigit;
char *secondNumber = 0;
printf("digit ");
scanf("%d *[^\n]", &firstDigit);
fgets(firstNumber, firstDigit, stdin);
printf("%s \n", firstNumber);
}
The code here gives me null as firstNumber while it clearly should just be a string.
here is the results of running this code:
$ ./result.exe
digit 2
12
(null)
CodePudding user response:
I had envisioned leaving just comments, but it is clear you have a misconception about the use of fgets()
and scanf()
. Continuing from my comments, let's see if we can help.
First, a pointer is a normal variable that holds the memory address as its value. When you declare a pointer, it is uninitialized (setting the pointer NULL
or 0
doesn't provide a valid address to anything). Before you attempt to access the memory address held by the pointer, that memory address must be a valid memory address you can read or write to.
Since you attempt to use firstNumber
with fgets()
, the memory address held by firstNumber
must be the starting address for a sufficient number of characters to hold what you are reading. The easiest way to provide that is simply to declare firstNumber
as a character-array large enough to hold the user input. (and since an array is converted to a pointer to the first element on access, you simply use the array name as your pointer)
Second, when you learn enough about how scanf()
works to understand the pitfalls it presents to the new C programmer, you will understand it is far better to read user input with fgets()
and then convert the input to what you need using sscanf()
instead of scanf()
. Any time you take user-input or attempt a numeric conversion, you cannot use either function correctly unless you check the return to determine if the input or conversion succeeded or failed.
Since you want to read a sequence of characters and then convert the input to an integer value, simply declare firstNumber
as a character array, read the user input into the array and then attempt to convert the contents of firstNumber
to the integer firstDigit
(if you just want the first ASCII digit in the user-input, that is simply firstNumber[0]
, no conversion required)
On the other hand, if you want to convert the entirety of what the user entered into an integer, just use sscanf()
in the same manner you would use scanf()
, except you read from the buffer firstNumber
instead of stdin
.
Now, understand fgets()
reads the '\n'
generated by the user pressing Enter into the buffer it fills. While it isn't necessary to remove it for the conversion to int
, it is often necessary if you want to use the buffer as a string and don't want any dangling '\n'
handing off the end. Thankfully it is easy to do with strcspn()
.
Putting it altogether to read the user-input into firstNumber
and convert that string representation of an integer into an int
, you could do:
#include <stdio.h>
#include <string.h> /* for strcspn() */
#define MAXC 1024 /* if you need a constant, #define one (or more) */
int main () {
int firstDigit = 0;
char firstNumber[MAXC];
fputs ("digit: ", stdout); /* no conversion, fputs is fine */
/* use firstNumber as a temporary buffer to hold input, validate
* fgets succeeds, otherwise user canceled with manual EOF
* ctrl d (or ctrl z on windows)
*/
if (!fgets (firstNumber, sizeof firstNumber, stdin)) {
puts ("(user canceled input)");
return 0;
}
/* trim '\n' from end of buffer by overwriting with nul-character
* optional -- used for outputting firstNumber as string.
*/
firstNumber[strcspn (firstNumber, "\n")] = 0;
/* now parse firstDigit from buffer with sscanf() */
if (sscanf (firstNumber, "%d", &firstDigit) != 1) {
fputs ("error: invalid integer.\n", stderr);
return 1;
}
printf ("\nfirstNumber contains string: \"%s\"\n"
"FirstDigit contains integer: %d\n",
firstNumber, firstDigit);
}
Understanding this wasn't your ultimate goal, this should provide all the basic building blocks you need to move forward reading input from the user and handling any conversions required.
Example Use/Output
$ ./bin/firstnumdigit
digit: 24371
firstNumber contains string: "24371"
FirstDigit contains integer: 24371
Or what happens if the user screws up (they will)
$ ./bin/firstnumdigit
digit: two hundred twenty one
error: invalid integer.
And handling the manual EOF
indicating the user canceled input:
$ ./bin/firstnumdigit
digit: (user canceled input)
Look things over and let me know if you have questions.
CodePudding user response:
fgets
doesn't change firstNumber
. It can't possibly change firstNumber
since C passes by value. So firstNumber
still has the value you gave it, NULL
.
What fgets
is supposed to do is write to the memory to which firstNumber
points. Passing NULL
as you are doing is therefore an error. You need to pass a pointer to enough memory to hold the value you want. The second argument is the size of that memory.
CodePudding user response:
firstNumber
is a string, but as you set it to NULL
at its declaration fgets
can't write anything into it. The program so comes across a segfault.
You should init firstNumber
with malloc
, or change its declaration to char firstNumber[64]