Storing and retrieving strings in Multidimensional array - c

I have the following code which stores string-input from a user N times in a multidimensional array. And then print out the second element.
main()
{
// Array to store 10 strings, 20 characters long.
char strStorage[10][20];
printf("\nEnter how many strings: ");
scanf( "%d" , &num);
fflush(stdin);
for ( count = 0 ; count < num ; count++)
{
printf("Enter a string: ");
gets(strStorage[count]);
fflush(stdin);
}
printf("%s", strStorage[2]);
Last line prints out garbage. The user-input is not visible inside the garbage hence either my element access is wrong or my storage is wrong. Can anyone help me with regards to what is the problem?
Thanks in advance...

strStorage[2] is the third string, so if num is less than 3, you won't initialize it and it will contain garbage.

scanf("%d", &num); doesn't ensure that num contains a value. Perhaps it'd be wise to check the return value of scanf to ensure it read 1 value, like this: if (scanf("%d", &num) != 1) { puts("Error reading integer"); }
While we're on this topic, I presume num and count are declared as an int, and you've hidden the declarations from us. Tsssk! Do you want our help? If so, then make your code compilable! Do you really think int is suitable for storing indexes to arrays? It's possible that they might have negative values. I'd suggest using size_t, instead, and the %zu format specifier tells scanf to expect a size_t value from stdin.
... and what happens when that size_t contains a value greater than the number of elements in your array? I suggest researching variable length arrays.
fflush(stdin); is nonsense because fflush defines behaviour for files open for output, and stdin is a file open for input only. That's sort of like flushing the toilet and expecting the waste to come out of the bowl, rather than going down through the S-bend. Perhaps you mean to discard the remainder of a line, because you've read the data you need from the start of it. Something like for (int c = getchar(); c >= 0 && c != '\n'; c = getchar()); might work.
Don't use gets. Use fgets(strStorage[count], sizeof strStorage[count], stdin); instead, to ensure that no buffer overflows occur.
There, I think I covered just about every bit of undefined behaviour and nit-picky stuffs.

Related

Missing value with scanf in C89

Hope you guys can help me with a problem I'm having.
So I have this C code snippet:
int i = 0;
int q = 0;
scanf("%d %d", &i, &q);
When the user enters 4 5, the values 4 and 5 are stored in i and q respectively.
But when the user enters 99.99, 99 is stored in i, but the other 99 after the point goes missing. I do know how scanf works and I understand that scanf will stop scanning after ., but where does the second value go to?
Even if I do:
int i = 0;
int q = 0;
int k = 0;
scanf("%d %d", &i, &q);
scanf("%d", &k);
I still cant get the second value. Where does the second value go and how can I get store it in my variable?
It is trying to look for integer but it is not integer that is left in stdin so it fails.
You can get desired behavior if you do this
int a,b;
scanf("%d.%d",&a,&b);
printf("%d,%d",a,b);
This prints 99,99 as expected.
For your information,
scanf stops at the first mismatch and leaves the rest of the target objects untouched.
Also the unmatched data is left in the input buffer, available for a subsequent read using scanf etc.
Also you can check the return value to determine how many "items" scanf matched.
scanf() doesn't ignore the . while expects to read an int. I suggest you use fgets() and then try to parse with sscanf() which is a better approach. Something like:
#include <stdio.h>
int main(void)
{
int i = 0;
int q = 0;
char line[256];
if (fgets(line, sizeof line, stdin)) {
if (sscanf(line, "%d.%d", &i, &q) == 2) {
printf("i=%d, j=%d\n", i, q);
} else {
printf("Coudn't scan 2 ints\n");
}
} else {
printf("Couldn't read a line\n");
}
}
Note that fgets() will also read in the newline character if there's space in the buffer. It doesn't matter in this case.
But you need to be aware of it and may be undesirable in some cases (e.g., reading a name).
Also see: Why does everyone say not to use scanf? What should I use instead?
Let X be the following statement...
I do know how scanf works
Let Y be the following statement...
... but where does the second value go to?
X and Y do not correspond. Either you know about the return value of scanf, or you don't know how scanf works. That's the bottom line.
... but where does the second value go to?
According to the fscanf manual,
The fscanf() functions shall execute each directive of the format in turn. If a directive fails, as detailed below, the function shall return. Failures are described as input failures (due to the unavailability of input bytes) or matching failures (due to inappropriate input).
The space directive won't match the . input, which will cause a matching failure, scanf will return, meaning that nothing beyond the . byte will be consumed from stdin. In fact, scanf will even put the . back into stdin for you, just before it returns... Isn't that nice?
I gather you understand this (because you said "I do know how scanf works"), yet you seem to be asking about that second value which couldn't have been read due to a previous matching failure... thus, the answer to your first question is, the second value doesn't exist. It can't exist yet, because an input format error exists prior to it.
While we're on the topic of scanf, return values and matching failures, for the remaining question I'm going to assume your code actually looks something more like this:
int i = 0;
int q = 0;
if (scanf("%d %d", &i, &q) != 2) {
puts("Discarding invalid input");
scanf("%*[^\n]"); // discard up to the next newline and...
getchar(); // discard that newline, too.
// XXX: You might want to `return` or `continue` or something
}
... and how can I get store it in my variable?
As mentioned earlier, the space directive doesn't match the period. You need to replace that with something which manipulates the input stream as you intend... That's difficult for me to answer, because I don't have that information, but here's what I'd suggest: Split the two conversions up into two separate calls to scanf. This should give you a nice place in between the two calls to scanf to insert your period-handling code.
Here's a before & after, side-by-side, of the idiom I've adopted for that kind of input:
// BEFORE // AFTER
if (scanf("%d %d", &i, &q) != 2) { if (scanf("%d", &i) != 1) {
// ... puts("Invalid first input...");
// XXX: Handle this???
// XXX: `return` or `continue` or something
}
// XXX: Read a character, check if it's a space (or a dot, or something else which you have in your mind and I don't have in mine)
if (scanf("%d", &q) != 1) {
// ...
Handling the erroneous period could be as simple as exiting the process or calling getchar() to discard a single character, then continueing in order to try again. These solutions won't solve all user input errors, and might even confuse or frustrate some users. I recommend sticking with the discard the rest of the line method, at least until you learn about all of the alternatives for user input and what they're each best at. After all, people tend to avoid using software which confuses them...
... hence the reason people tend to discourage scanf... because I guess there's no such thing as literature which sets a standard, and thus there's no way to correct my scanf-related misunderstandings.

Inputting a string with spaces in C

I want my program to prompt the user for how many sentences they want to write and then enter those sentences. However, when I try entering the sentences, I keep getting errors. I tried using several different fucntions but all of them gave some kind of error. For example, right now I am trying to use fgets() and after I enter the first sentence it gives me a segmentation fault. Can someone tell me what is the best way to take input for a string with spaces and how to fix my problem?
int n;
char str[n][80];
printf("Enter number of lines: ");
scanf("%d", &n);
printf("Enter a sentecne: ");
for(int i = 0; i < n; i++){
fgets(str[i], 80, stdin);
printf("%s", str[i]);
}
You define the array str before you initialize n. That means n will have an indeterminate value (which will be seemingly random).
Move the input of n to before you define str.
you can use read function http://man7.org/linux/man-pages/man2/read.2.html
reading on the file descriptor 0 (standart input), a char *buffer to store your data, and a size_t size to read
there are several problems in your code
int n; // must have a value
int n = 10; // example, here your variable is initialized
you also don't check the return value of scanf

Scanf for multiple user inputs

Apologizes I am very inexperienced with C. I have the following code:
char * a[BUF_SIZE];
scanf("%d", numberOf);
do {
a[i] = (char *)malloc(MAX_LINE_LEN + 1);
scanf("%s", a[i]);
++i;
} while(i < numberOf);
The idea is simple, read two inputs from stdin using scanf, the first being a single int, followed by some array of strings. Scanf works independently in both cases e.g. scanf("%d", numberOf) will store a digit and scanf("%s", a[i]) will store a set of strings into the array. However in conjunction reading an integer first into numberOf causes a segfault when reading in a set of strings. My question is why? I know its generally bad practice to use scanf, but I fail to see how reading in multiple inputs from stdin can cause a segfault in the resulting code. Much Thanks!
From the code, it looks like numberOf is an int. When using scanf, you want to pass it a pointer, so change scanf("%d", numberOf); to scanf("%d", &numberOf);
What scanf does is take the user input and put it into the memory address specified by the second parameter. When you provide an int as the second parameter, scanf tries to put user input into a memory address (specified by the int) that it may not own, causing the seg-fault.
You are missing & operator in scanf("%d", numberOf); put it as &numberOf

Am I using scanf incorrectly?

Each line of input is a line with a command followed by numbers (except in the exit case).
I cannot figure out what I am doing wrong. This segment is looking for the store command and then does the action store entails:
char command[20];
while(strcmp(command, "exit") != 0)
{
/*scans for command strings inputted*/
scanf(" %s", command);
/* handles store command*/
if(strcmp(command, "store") == 0)
{
memory[0] = 1;
scanf("%d %d %d %d %d", &startx, &starty, &finishx, &finishy, &number);
for( i = startx; i < finishx; i++)
{
for(j = starty; j < finishy; j++)
{
square[i][j] = number;
}
}
}
}
Yes, you are using it wrongly(a). The line:
scanf(" %s", command);
has no bounds checking on the input. If someone enters more than 19 characters into your program, it will overflow the char command[20] and result in undefined behaviour.
The two major problems with scanf are:
using it with an unbounded %s since there's no way to control how much data is entered. My favourite saying is that scanf is to scan formatted information and there's not much less formatted than user input.
not checking how many items were scanned - it's possible to scan less than you expected.
If you want to do it right, see here. It uses fgets to get a line, protecting from buffer overflows and detecting problems.
Once you have the line as a string, you can safely sscanf it to your heart's content, since you know the upper bound on the length and you can always return to the start of the string to re-scan (not something easy to do with an input stream).
Other problems with your code include:
The initial strcmp on an uninitialised buffer. It could actually be (arbitrarily) set to exit which would cause your loop not too start. More likely is that it's not a valid C string at all, meaning strcmp will run off the end of the buffer. That won't necessarily end well.
No checking that all your numeric items were entered correctly. You do that by checking the return value from scanf (or sscanf should you follow my advice on using the rock-solid input function linked to here) - it should be five but entering 1 hello 2 3 4 would result in a return code of one (and all but startx unchanged).
No range checking on input. Since square has limited dimensions, you should check the inputs to ensure you don't write outside of the array. That's both numbers that are too large and negative numbers.
(a) Syntactically, what you have is correct. However, from a actual semantic point of view (i.e., what you mean to happen vs. what may happen), there's a hole in your code large enough to fly an Airbus A380 through :-)

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