How to add few indata parameters using gets(tmp)? - c

int regMedicine(Medicine lakemedel[], int antalMedicine)
{
char namnMed[WORDLENGTH], tmp[WORDLENGTH], test[WORDLENGTH] = "ja";
int storlek, saldo;
while(strcmp(test, "ja") == 0)
{
printf("Ange namn: ");
gets(namnMed);
printf("Ange storlek: ");
while(tmp!=0){ ///////////////////////
gets(tmp); //////////////////////////////////////////
} ///////////////////////////////////
storlek = atoi(tmp); //atoi - converts string to int
printf("Ange saldo: ");
gets(tmp);
saldo = atoi(tmp); //atoi - converts string to int
lakemedel[antalMedicine] = createMedicine(namnMed, storlek, saldo);
antalMedicine++;
printf("Vill du fortsatta registrera (ja) eller (nej): ");
gets(test);
}
return antalMedicine;
}
I am writing a program where I use a FILE to register the medicine, size of the medicine and balance.
I wrote a function where I can take the name of medicine, size and balance. But the problem I got stuck is how to add few sizes of medicine and quit by entering "0". Any Ideas? Should I use an extra loop?

gets is an obsolete function and should never be used. Why is the gets function so dangerous that it should not be used?
while(tmp!=0) doesn't make any sense, this checks the target array address against null, which isn't what you want. Instead of this loop, make one checking the result of fgets. Examples: Removing trailing newline character from fgets() input. You can use fgets either on stdin (command line input) or directly from the FILE pointer.
Avoid atoi since it doesn't handle errors well. Instead use strtol, for example strtol(str, NULL, 10) where str is the string and 10 is decimal format (base 10).
Avoid writing source code in your native language, since C itself is based on English. It gets confusing when you have to ask for help by English-speaking programmers (such as in this site) and it also gets confusing in general for those reading the code.
I'm Swedish myself so I can read this, yet the "Swenglish" is much harder for me to read than source code written in pure English. There's also the nasty letters åäö which will eventually cause technical problems.
User messages can of course be in the native language, but that's another story.

how to add few sizes of medicine and quit by entering "0". Any Ideas? Should I use an extra loop?
Certainly, if you want to repeat entering size and balance, you'd use a loop, e. g. you could replace
printf("Ange storlek: ");
while(tmp!=0){ ///////////////////////
gets(tmp); //////////////////////////////////////////
} ///////////////////////////////////
storlek = atoi(tmp); //atoi - converts string to int
printf("Ange saldo: ");
gets(tmp);
saldo = atoi(tmp); //atoi - converts string to int
lakemedel[antalMedicine] = createMedicine(namnMed, storlek, saldo);
antalMedicine++;
with
while (printf("Ange storlek (avsluta genom att ange 0): "),
fgets(tmp, sizeof tmp, stdin) && (storlek = strtoul(tmp, NULL, 10))
)
{
printf("Ange saldo: ");
if (!fgets(tmp, sizeof tmp, stdin)) break; // leave loop on input end
saldo = strtoul(tmp, NULL, 10);
lakemedel[antalMedicine++] = createMedicine(namnMed, storlek, saldo);
}

Related

Nested if statement in C - why doesn't it evaluate the last else if?

The following code does not execute the last else if statement when you assign to choice value 3.
#include<stdio.h>
#include<stdlib.h>
int main() {
puts("Specify with a number what is that you want to do.");
puts("1. Restore wallet from seed.");
puts("2. Generate a view only wallet.");
puts("3. Get guidance on the usage from within monero-wallet-cli.");
unsigned char choice;
choice = getchar();
if ( choice == '1' ) {
system("nice -19 ~/monero-x86_64-linux-gnu-v0.17.2.0/monero-wallet-cli --testnet --restore-deterministic-wallet");
exit(0);
}
else if ( choice == '2' ) {
system("nice -19 ~/monero-x86_64-linux-gnu-v0.17.2.0/monero-wallet-cli --testnet --generate-from-view-key wallet-view-only");
exit(0);
}
else if ( choice == '3' ) {
puts("Specify with a number what is that you want to do.");
puts("1. Get guidance in my addresses and UTXOs");
puts("2. Pay");
puts("3. Get guidance on mining.");
unsigned char choicetwo = getchar();
if ( choicetwo == '1' ) {
printf("Use \033address all\033 to get all your addresses that have any balance, or that you have generated at this session.");
printf("Use \033balance\033 to get your balance");
printf("Use \033show_transfers\033 to get ");
printf("Use \033show_transfers\033 out to get ");
printf("Use \033show_transfers in\033 to get your balance");
}
}
return 0;
}
I get the following output When I enter 3:
Specify with a number what is that you want to do.
1. Restore wallet from seed.
2. Generate a view only wallet.
3. Get guidance on the usage from within monero-wallet-cli.
3
Specify with a number what is that you want to do.
1. Get guidance in my addresses and UTXOs
2. Pay
3. Get guidance on mining.
I'm really blocked, something is missing and I have no clue why it does not proceed to take the input from the user for the second time.
When you enter "3" for the first input, you're actually inputting two characters: the character '3' and a newline. The first getchar function reads "3" from the input stream, and the second one reads the newline.
After accepting the first input, you'll want to call getchar in a loop until you read a newline to clear the input buffer.
choice = getchar();
while (getchar() != '\n');

C: Scanf in while loop executes only once

I am trying something simple in C, a program to get the exchange and do some conversions.
To make sure scanf gets the right type I placed it into a while loop, which continues to ask for input until a number is inserted.
If I enter a character instead of a number it does not ask again for an input.
exRate = 0;
scanfRes = 0;
while(exRate <= 0){
printf("Enter the exchange rate:");
while(scanfRes != 1){
scanfRes = scanf(" %f", &exRate);
}
if(scanfRes == 1 && exRate > 0){
break;
}
printf("Exchange rate must be positive.\n");
}
UPDATE: As this is a course assignment, I was not supposed to use anything outside of the taught material. When I asked the academic staff about handling unexpected input, I got an answer that this is a scenario I am not supposed to take into consideration.
The answers and help in the comments is all useful and I added 1 to all useful suggestions. The staff answer makes this question no longer needed.
Change handling of scanf() result.
If the input is not as expected, either the offending input data needs to be read or EOF should be handled.
for (;;) {
printf("Enter the exchange rate:");
scanfRes = scanf("%f", &exRate);
if (scanfRes == 0) {
printf("Exchange rate must be numeric.\n");
// somehow deal with non-numeric input, here just 1 char read & tossed
// or maybe read until end-of-line
fgetc(stdin);
} else if (scanfRes == EOF) {
// Handle EOF somehow
return;
} exRate > 0){
break;
}
printf("Exchange rate must be positive.\n");
}
Note: the " " in " %f" is not needed. "%f" will consume leading white-space.

Troubles appending structure to file in C

I'm having some trouble to append a structure to a file:
OS: Ubuntu 14.04
Struct:
struct baris
{
char name[30];
char trusted[1];
int phone;
int id;
};
Func:
addNewBariga()
{
char answer[30];
struct baris new;
while(1){
printf("Enter new Barigas' ID please.");
scanf("%d",&new.id);
printf("Enter new Barigas' name please.\n");
scanf("%s",new.name);
printf("Enter new Barigas phone please. \n");
scanf("%d", &new.phone);
printf("Is Bariga trusted?\n\t[Y/N]:");
scanf("%s",new.trusted);
while(1)
{
if(strcmp(new.trusted,"Y") != 0 && strcmp(new.trusted,"y") != 0)
{
printf("%s",new.trusted);
printf("\nWrong command givven.\t\n[Y/N]:");
scanf("%s",&new.trusted);
}
else
break;
}
printf("Values you've entered:\n\tID:%d\n\tName: %s\n\tPhone: %d\n\tTrustworth:%s\nWould you like to proceed to saving?\n[Y/N]:\n",new.id,new.name,new.phone,new.trusted);
scanf("%s",&answer);
if(strcmp(answer,"Y") ==0 || strcmp(answer,"y")==0) //Process to saving
{
printf("saving...");
confPtr = fopen(filePath , "ab");
//fwrite(new.id, sizeof(new.id), 1, confPtr);
fwrite(&new, sizeof(struct baris), 1, confPtr);
fclose(confPtr);
break;
}
}
What I'm getting:
fabio\00\00\00\00\00\00\00\00\00fab\00\00\00\00\00\00\00\00\00fab\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 <1\B5y\00\00\00\00\00\00\00fab\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00 \C5f\DAy\00\00\00\00\00\00\00
That output looks basically correct, what did you expect?
You're writing binary data to a binary file. Binary files are not very easy to inspect manually.
The first member of the structure, name, will always be 30 bytes long in the output for example.
Note as pointed out by #BLUEPIXY in a comment that this:
scanf("%s",new.trusted);
triggers undefined behavior if a non-zero length is entered, since trusted is only 1 character long that is consumed by the string terminator. You should increase its length, or (much better!) stop using direct scanf() like this and instead read a whole line of input with fgets() and parse it using sscanf().
Also, when using functions that can fail (like scanf(), sscanf() or fgets()) you must check the return values before relying on them to have succeeded.

Having trouble comparing strings in file to an array of strings inputted by user in C

I have tried to research this question, but was unable to find anything that would help me. I have been constantly trying to debug using fprint, but I still cannot figure it out.
I am an intermediate programmer, and would love if I could get some help here. Here is my code:
int i = 0;
const int arraySize = 10;
char buf[256];
char str[256];
char buffer[256];
char *beerNames[arraySize] = { };
FILE *names;
FILE *percent;
i = 0;
int numBeers = 0;
printf("Please enter a name or (nothing to stop): ");
gets(buf);
while (strcmp(buf, "") != 0) {
beerNames[i] = strdup(buf);
i++;
numBeers++;
if (numBeers == arraySize)
break;
printf("Please enter a name or (nothing to stop): ");
gets(buf);
}
// now open files and look for matches of names: //
names = fopen("Beer_Names.txt", "r");
percent = fopen("Beer_Percentage.txt", "r");
while (fgets(str, sizeof(str) / sizeof(str[0]), names) != NULL) {
fgets(buffer, sizeof(buffer) / sizeof(buffer[0]), percent);
for (i = 0; i < numBeers; i++) {
if (strcmp(str, beerNames[i]) == 0) {
printf("Beer: %s Percentage: %s\n", str, beerNames[i]);
break;
}
}
}
fclose(names);
fclose(percent);
So, the issue that I am having is when I try to strcmp(), it is not comparing properly and is returning either a -1 or a 1. I have tried printing out the strcmp() values as well and it just ends up skipping the match when it equals to 0.
My Beer_Names.txt (shortened) looks like this:
Anchor Porter
Anchor Steam
Anheuser Busch Natural Light
Anheuser Busch Natural Ice
Aspen Edge
Big Sky I.P.A.
Big Sky Moose Drool Brown Ale
Big Sky Powder Hound (seasonal)
Big Sky Scape Goat Pale Ale
Big Sky Summer Honey Ale (seasonal)
Blatz Beer
Blatz Light
Blue Moon
And my Beer_Percentage.txt (shortened) looks like this:
5.6
4.9
4.2
5.9
4.1
6.2
5.1
6.2
4.7
14.7
4.8
0
5.4
This is not for a homework assignment, I am just doing a personal project and I trying to get better at C.
You're problem is that gets() does not return the newline character as part of the string, while fgets() does.
So when the user entered value "Anchor Porter" is read with gets, your string looks like this "Anchor Porter\0", but when you read it from a file with fgets it ends up like this "Anchor Porter\n\0", which will not compare equal.
gets(buf);
I know gets(3) is convenient, and I know this is a toy, but please do not use gets(3). It is impossible to write secure code with gets(3) and there is a reasonable chance that future C libraries might not even include this function. (Yes, I know it is standardized but we can hope future versions will omit it; POSIX.1-2008 has removed it.) Reasonable compilers will warn you about its use. Use fgets(3) instead.
while (fgets(str, sizeof(str) / sizeof(str[0]), names) != NULL) {
sizeof(char) is defined to be 1. This is unlikely to change, and you're unlikely to change the type of the array. It's generally not a big deal, but you cannot use a construct like this as often as you might suspect -- you can use it in this case only because str[] was declared in an enclosing scope of this line. If str were passed as a parameter, the sizeof(str) operator would return the size of a data pointer and not the size of the array. Don't get too used to this construct -- it won't always work as you expect.
names = fopen("Beer_Names.txt", "r");
percent = fopen("Beer_Percentage.txt", "r");
while (fgets(str, sizeof(str) / sizeof(str[0]), names) != NULL) {
fgets(buffer, sizeof(buffer) / sizeof(buffer[0]), percent);
Please take the time to check fopen(3) for success or failure. It's a good habit to get into, and if you provide a good error message, it might save you time in the future, too. Replace the fopen() lines with something like this:
names = fopen("Beer_Names.txt", "r");
percent = fopen("Beer_Percentage.txt", "r");
if (!names) {
perror("failed to open Beer_Names.txt");
exit(1);
}
if (!percent) {
perror("failed to open Beer_Percentage.txt");
exit(1);
}
You could wrap that up into a function that does fopen(), checks the return value, and either prints the error message and quits or returns the FILE* object.
And now, the bug that brought you here: Robert has pointed out that fgets(3) and gets(3) handle the terminating newline of input differently. (One more reason to get ridd of gets(3) as soon as possible.)

Why does my program read an extra structure?

I'm making a small console-based rpg, to brush up on my programming skills.
I am using structures to store character data. Things like their HP, Strength, perhaps Inventory down the road. One of the key things I need to be able to do is load and save characters. Which means reading and saving structures.
Right now I'm just saving and loading a structure with first name and last name, and attempting to read it properly.
Here is my code for creating a character:
void createCharacter()
{
char namebuf[20];
printf("First Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].fname,namebuf);
printf("Last Name:");
if (NULL != fgets(namebuf, 20, stdin))
{
char *nlptr = strchr(namebuf, '\n');
if (nlptr) *nlptr = '\0';
}
strcpy(party[nMember].lname,namebuf);
/*Character created, now save */
saveCharacter(party[nMember]);
printf("\n\n");
loadCharacter();
}
And here is the saveCharacter function:
void saveCharacter(character party)
{
FILE *fp;
fp = fopen("data","a");
fwrite(&party,sizeof(party),1,fp);
fclose(fp);
}
and the loadCharacter function
void loadCharacter()
{
FILE *fp;
character tempParty[50];
int loop = 0;
int count = 1;
int read = 2;
fp= fopen("data","r");
while(read != 0)
{
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
}
fclose(fp);
}
So the expected result of the program is that I input a name and last name such as 'John Doe', and it gets appended to the data file. Then it is read in, maybe something like
1. Jane Doe
2. John Doe
and the program ends.
However, my output seems to add one more blank structure to the end.
1. Jane Doe
2. John Doe
3.
I'd like to know why this is. Keep in mind I'm reading the file until fread returns a 0 to signify it's hit the EOF.
Thanks :)
Change your loop:
while( fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp) )
{
// other stuff
}
Whenever you write file reading code ask yourself this question - "what happens if I read an empty file?"
You have an algorithmic problem in your loop, change it to:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
while(read != 0)
{
//read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
loop++;
count++;
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
}
There are ways to ged rid of the double fread but first get it working and make sure you understand the flow.
Here:
read=fread(&tempParty[loop],sizeof(tempParty[loop]),1,fp);
printf("%d. %s %s\n",count,tempParty[loop].fname,tempParty[loop].lname);
You are not checking whether the read was successful (the return value of fread()).
while( 1==fread(&tempParty[loop],sizeof*tempParty,1,fp) )
{
/* do anything */
}
is the correct way.
use fopen("data","rb")
instead of fopen("data","r") which is equivalent to fopen("data","rt")
You've got the answer to your immediate question but it's worth pointing out that blindly writing and reading whole structures is not a good plan.
Structure layouts can and do change depending on the compiler you use, the version of that compiler and even with the exact compiler flags used. Any change here will break your ability to read files saved with a different version.
If you have ambitions of supporting multiple platforms issues like endianness also come into play.
And then there's what happens if you add elements to your structure in later versions ...
For robustness you need to think about defining your file format independently of your code and having your save and load functions handle serialising and de-serialising to and from this format.

Resources