Adding data to arrays in C - c

I have a few arrays that I wanted to update. The problem is that when data is added to the array, some variables are updated to 0.
my code to add data:
void addStockItem(){
system(CLS_NAME);
printf("New Item\n\n");
printf("New Item Name : ");
fflush(stdin);
scanf(" %[^\n]s",&*itemName[totalItem]);
//itemName[totalItem][30] = strupr(itemName[totalItem]);
fflush(stdin);
printf("New Item Price : ");
scanf("%f",&item_Price_Profit[totalItem][0]);
printf("New Item Profit : ");
scanf("%f",&item_Price_Profit[i][1]);
printf("New Item Qty : ");
scanf("%d",&itemQuantity[totalItem][0]);
itemQuantity[totalItem][1]=0;
itemQuantity[totalItem][2]=0;
++totalItem;
allStocks();
}
the data,
int totalItem=13,itemQuantity[][3]={8,0,0,9,0,0,11,0,0,0,0,0,20,0,0,22,0,\
0,16,0,0,18,0,0,9,0,0,7,0,0,5,0,0,12,0,0,0,0,0},sessionQuantity;
float item_Price_Profit[][2]={1,0.5,2,0.2,3,0.2,4,0.2,5,0.5,6,0.8,7,0.5,8,0.2,9,\
0.2,10,0.2,11,0.5,12,0.8,13,0.9};
char itemName[][30]={"STABILO PENCIL 2B","STABILO PEN 0.5",\
"STABILO ERASER","STABILO RULER","STABILO TEST PAD","STABILO BOOK","STABILO SCISSORS","STABILO SHARPENER","STABILO GLUE","STABILO CHALK","STABILO MARKER PEN","OXFORD DICTIONARY","STABILO HIGHLIGHTER"};
full code: http://pastebin.com/jjuCCrjz
[EDIT]
Everything work as they intended to after I changed itemQuantity[][3] to itemQuantity[100][3], item_Price_Profit[][2] to item_Price_Profit[100][2] and itemName[][30] to itemName[100][30]. What could possibly my mistake other than scanf?

I can't access pastebin from my work computer, so I'll have to go by what's posted.
Several issues off the bat:
fflush is only defined to work on output streams, not input streams; the behavior of fflush(stdin) is undefined (it will do something, but probably not what you want). If you need to clear out garbage from the input stream, you'll need to consume it using getchar() or fgets() or similar until you see a newline or some other indicator that you've cleared out the garbage. The %f and %d conversion specifiers will skip over any leading whitespace, and by having the blank before the %[ conversion specifier will also cause any leading whitespace to be skipped. So ditch the fflush calls altogether.
scanf(" %[^\n]s",&*itemName[totalItem]); - this looks confused. Unless you expect the input to always have a trailing s character, the conversion specifier should simply be %[^\n]. The &* in front of itemName is redundant; you just need to write
scanf(" %[^\n]", itemName[totalItem]);Although you should probably put a field width specifier in there:
scanf(" %30[^\n]", itemName[titalItem]);
to avoid buffer overflow.
You're accessing all your data items (totalItem, itemName, item_Price_Profit, etc.) as global variables. This is usually a recipe for heartburn. Ideally, functions and their callers should not share state via globals; rather, they should communicate through parameters, return values, and exceptions (where supported). Something more like
void addStockItem(char *name, float *price, float *profit, float *quantity)
{
...
scanf(" %30[^\n]", name);
...
scanf("%f", price);
...
scanf("%f", profit);
...
scanf("%d", quantity);
} which would be called like
addStockItem(itemName[totalItem],
&item_Price_Profit[totalItem][0],
&item_Price_Profit[i][1],
&itemQuantity[totalItem][0]);
Your data structures feel really hinky to me, but that's likely because I can't see your entire program.

This:
scanf(" %[^\n]s",&*itemName[totalItem]);
can't be right. This is passing a character converted to a pointer, where scanf() expects a pointer to character. You probably mean:
scanf(" %[^\n]s", itemName[totalItem]);

Related

Why is scanf failing to read inputs correctly?

I cant figure out whats wrong. Am i using format specifiers in wrong way? Someone please help i am very new to coding.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char name[20];int age;char grade;double gpa;char area[10];
printf("User Input\n");
printf("Enter your name: ");
fgets(name,20,stdin);
printf("Your name is %s\n",name);
printf("Enter your age: ");
scanf("%d\n",&age);
printf("Your age is %d\n",age);
printf("Enter you grade: ");
scanf("%c\n",&grade);
printf("Your grade is %c\n",grade);//Why is this giving an int output?
printf("Enter your gpa: ");
scanf("%f\n",&gpa);
printf("Your gpa is %f\n",gpa);
printf("Enter your area: ");
scanf("%s\n",&area);
printf("Your area is %s",area);//This shows grade input
return 0;
}
Output
You use fgets correctly when reading name. I'd recommend also using fgets for all your other inputs, and then parsing the intended values out of them. For example:
char age_str[20];
fgets(age_str, 20, stdin);
age = strtol(age_str, NULL, 10);
This is preferable to using scanf directly for non-string inputs since if input fails to match a format string, it will remain in stdin and screw up the other scanf calls.
If you would like to use scanf correctly:
Check its return value to see if it matches the number of format specifiers in the string. If not, some inputs were not successfully read. You may want to use a do/while loop for this.
Begin your format strings with a space, as in " %c", so that any whitespace remaining in stdin will be skipped over.
Don't end your format strings with a newline.
Some things to remember about scanf:
Most conversion specifiers like %s, %d, and %f will skip over leading whitespace - %c and %[ will not. If you want to read the next single non-whitespace character, use " %c" - the leading blank tells scanf skip over any leading whitespace before reading the next non-whitespace character;
For what you are trying to do, you should not use \n in your format strings - it will cause scanf to block until you enter a non-whitespace character;
You do not need to use the & operator on array expressions like area; under most circumstances, array expressions are converted to pointer expressions1. Honestly, you should read area the same way you read name, using fgets (and you should always check the result of fgets), or you should specify the maximum field width in the specifier: scanf( "%9s", area ); (a 10-element array can hold up to a 9-character string, since one element has to be reserved for the string terminator);
You should get in the habit of checking the result of scanf - it will return the number of successful conversions and assignments. For example, scanf( "%d %d", &x, &y ) will return 2 if both x and y are read successfully. It will return EOF if end-of-file is signaled or there's a read error.
scanf will read up to the next character that doesn't match the conversion specifier - IOW, if you're using %d, then scanf will skip over any leading whitespace, then read up to the next character that isn't a decimal digit. That character is left in the input stream. This means if you're using %d and type in 123e456, scanf will read up to that 'e' character and assign 123 to the target. If you try to read again with %d, scanf will immediately stop reading on that e and return 0 without assigning anything to the target (this is called a matching failure). This will continue until you remove that 'e' from the input stream (such as with getchar or fgetc or scanf with the %c specifier, etc.
You need to make sure the types of the arguments match the format specifier. %s expects an argument of type char *, %d expects int *, %f expects float *. %x expects unsigned int *, %lf expects double *, etc.
This is one of the "deeply unintuitive" aspects of C I was talking about in my comment.

Can't understand why I can't loop %[^/n]

I can't seem to find where the problem is in here.
During the first loop, I can enter the name of the creditor but I can't do that during the second loop.
int main(){
float cb,ir,si,sum=0,totaldebt;
int time,i;
char name[25];
printf("------------Welcome to Debt Management System-------------");
for (i=1;i>=1;i++){
printf("\n%d)Name of the creditor: ",i);
scanf("%[^\n]",&name);
printf("Enter your current balance: ");
scanf("%f",&cb);
printf("Enter its interest rate: ");
scanf("%f",&ir);
printf("Enter time for the loan: ");
scanf("%d",&time);
si=cb*ir*time/100;//simple interest
totaldebt=si+cb; //simple interest + current balance
if (name=='none'){
break;
}
sum+=totaldebt;
}
It skip the scanf part and I somewhat guess that the reading part seems stuck by it's previous reading.
To get the effect you seem to be after, %[^\n]*c should be %[^\n]%*c. You need a specifier for the first pattern and then a specifier for a single character. The way you have it written now has you asking scanf to match everything up to a newline, and then read the sequence *c.
It can't read that sequence, but it matches the first specifier. So you end up with an unconsumed newline that is probably tripping your other input.
There's also the potential problem of your for (i=1;i>=1;i++), that condition is fishy, and likely to go on for a while.
Now, while this is all probably a fun exercise, I suggest you ditch scanf and switch to fgets to read lines of input. It's less cryptic, and it forces you to pass a buffer size, which makes using it somewhat easier and safer compared to scanf.
To complete the first answer, I noticed this problem:
if (name=='none')
{
break;
}
This form is not correct in C, you should:
use strcmp
function,
use " instead of ' to define a string:
/* if two strings are the same --but not necessary at the same adress-- strcmp return 0*/
if (0 == strcmp(name, "none"))
{
break;
}
While taking a string input you are not required to use the reference operator '&'. That's why in your first scanf statement use name instead of &name. Also modify the input statement with %*c if you want to take newline character in the input as shown below. Other errors have been stated in the above answers.
scanf("%[^\n]",name); OR
scanf("%[^\n]%*c",name);

The practical difference of %c vs %s

I'm required to do a seafood menu as an assignment in my college. I will provide the relevant code here:
int main ()
{
int a,d;
float c ;
char b,s,S,m,M,l,L;
printf ("\n\t\t\t\tSeafood Menu\n");
printf ("----------------------------------------------------------------------------------\n");
printf ("\t\t\t\t\t\t Dish Size\n");
printf ("Item Number\t Seafood Dish\t Small\t Medium Large\t\n");
printf ("----------------------------------------------------------------------------------\n");
printf ("\t 1\t Fried \t20.00 \t\t 40.00 \t\t 55.00\n");
//Continue with a bunch of menu here
printf (" Enter item number :");
scanf ("%d",&a);
printf (" Enter dish size (S/M/L) :");
scanf ("%s",&b);
if ((a==1)&&((b=='s')||(b=='S')))
{c=20.00;}
//continue with a bunch of condition to choose the price per dish stated in the menu
printf (" Enter dish quantity :");
scanf ("%d",&d);
printf (" Price per dish size :RM%.2f\n\n\n",c);
return 0;
}
When I tried to change the format identifier in this to %c, it just stopped accepting input for that particular scanf.
printf ("Enter dish size (S/M/L):");
scanf ("%s",b);
I would like to attach images but it seems that I am not allowed to do so 'll leave two links:
Normal, using %s: and abnormal, using %c
I'm curious about why it doesn't work when I use %c while %s works? As all I enter there is just character. Please enlighten me.
I'm curious about why it doesn't work when I use %c while %s works?
Well, guess what, it did not work, even if it appeared to.
As mentioned in the man page, for scanf(), the type of arguments are
%c expects a pointer to char
%s expects a pointer to the initial element of an char array.
Quoting C11, chapter §7.21.6.2, (emphasis mine)
c Matches a sequence of characters of exactly the number specified by the field
width (1 if no field width is present in the directive).
If no l length modifier is present, the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence. No null character is added.
s Matches a sequence of non-white-space characters.
If no l length modifier is present,the corresponding argument shall be a
pointer to the initial element of a character array large enough to accept the
sequence and a terminating null character, which will be added automatically.
In your case,
providing %s is wrong, as a single char is one element too short to scan and hold an array, that is null-terminated. This causes undefined behavior as memory overrun happens.
%c should have "worked" , if the input stream did not have the newline stored from previous ENTER key press. If you clean off the input stream of all pending inputs, you'll see it works. Use something like
scanf(" %c", &b); //the whitespace "eats up" all the previous whitespaces
You can see this previous answer of mine, for details on the same.

Scanf/Printf in C...what's going on here?

I am self-learning C and I am currently studying the Scanf and Printf functions.
I adapted this program to test myself:
char topping[24];
int slices;
int day, year;
float cost;
char month[10];
printf(" How much does a pizza cost in your area?\n");
printf("$");
scanf(" %f", &cost);
printf("What is your favorite one-word pizza topping?\n");
scanf(" %s",topping);
printf("How many slices of %s pizza, topping can you eat in one sitting\n",topping);
scanf(" %d", &slices);
printf(" What is today's date (enter in the following format 1-Jan-2016 )\n");
scanf(" %d-%s-%d", &day, month, &year);
printf("\nWhy not treat yourself to dinner on %d-%s-%d and have %d slices of %s pizza ? It will only cost you %.2f", day, month, year,slices, topping,cost);
The purpose of the exercise is for me to grasp an understanding of scanf functions and how "delicate" they can be.
My test program here runs well...except for the output in the year variable.
Why is the output in the year variable spitting out gibberish and how can I fix it?
Thank you.
Here's the problem. The %s specifier means to read any characters up until the next whitespace. So , after %d- has matched 1-, then the %s matches Jan-2016. Then the next %d fails as there is nothing left to match.
First of all you should always be checking the return value of scanf so you know whether there was a matching failure. For example in this case:
if ( 3 != scanf(" %d-%s-%d", &day, month, &year) )
{
printf("Matching failure occurred.\n");
// do something else...
}
else
{
printf("Why not treat yourself...
Secondly, to actually avoid the problem. The scanf function is pretty limited as you can see. To use other delimiters instead of whitespace, you can use the scanset specifier %[.....] instead:
scanf(" %d-%9[^-]-%d", &day, month, &year)
(with the same error checking). The scanset specifier means to read any characters (possibly including whitespace) that matches the characters inside the [], except that a ^ indicates to NOT match the next character. So this will read everything up until the next -. Also I added the 9 to avoid overflowing your buffer of size 9+1.
Of course this means if the person never types another - then the program goes a bit weird. You can fix this by making the format string more and more complicated; or you can instead read an entire line with fgets and then use the sscanf function with the aforementioned string. This will catch the case of the person pressing Enter before typing another -.
In fact it turns out it's usually a good idea to read a whole line at a time and then go back and process that line.
At some stage you will get tired of how awful scanf is, and make your own parser.

having trouble with a "\n" and scanf

Here is the code
printf("\n");
printf("Enter a integer vaule:");
scanf("%d" , &num3);
printf("You entered: %015d", num3);
printf("Enter a float value:");
scanf("%f", &deci3);
printf("You entered: %15.2f", deci3);
printf("\n");
the output is
Enter a integer vaule:4.4
You entered: 000000000000004
Enter a float value:You entered: 0.40
The problem is this code is not stopping at
printf("Enter a float value:");
and this scanf
scanf("%f", &deci3);
seems to be getting its value from the previous scanf
The %d conversion stops wherever the integer stops, which is a decimal point. If you want to discard the input there, do so explicitly… getc in a loop, fgets, or such. This also allows you to validate the input. The program should probably complain about 4.4.
The scanf function works this way per the specification:
An input item shall be defined as the longest sequence of input bytes (up to any specified maximum field width, which may be measured in characters or bytes dependent on the conversion specifier) which is an initial subsequence of a matching sequence. [Emphasis added.]
In your example, the following C string represents the contents of stdin when the first scanf call requests input: "4.4\n".
For this initial call, your format string consists of a single specifier, %d, which represents an integer. That means that the function will read as many bytes as possible from stdin which satisfy the definition of an integer. In your example, that's just 4, leaving stdin to contain ".4\n" (if this is confusing for you, you might want to check out what an integer is).
The second call to scanf does not request any additional input from the user because stdin already contains ".4\n" as shown above. Using the format string %f attempts to read a floating-point number from the current value of stdin. The number it reads is .4 (per the specification, scanf disregards whitespace like \n in most cases).
To fully answer your question, the problem is not that you're misusing scanf, but rather that there's a mismatch between what you're inputting and how you're expecting scanf to behave.
If you want to guarantee that people can't mess up the input like that, I would recommend using strtol and strtod in conjunction with fgets instead.
This works, but it dont complains if you type 4.4 for the int
#include <stdio.h>
int main() {
char buffer[256];
int i;
float f;
printf("enter an integer : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%d", &i);
printf("you entered : %d\n", i);
printf("enter a float : ");
fgets(buffer,256,stdin);
sscanf(buffer, "%f", &f);
printf("you entered : %f\n", f) ;
return 0;
}
use a fflush(stdin) function after the fist scanf(), this will flush the input buffer.

Resources