Re: Assigning a value to struct variables?
@2kaud: Sorry, can you please explain this line:
if (char *nl = strrchr(acct.name, '\n')) *nl = 0;
I haven't used that many libraries yet, except for stdio/stdlib/math, so please excuse me. And I'm really confused about the pointers (*). Can I get a layman explanation from you, 2kaud? All the stuff I've read so far can be a little bit too confusing for a beginner like me, unfortunately...
Re: Assigning a value to struct variables?
Quote:
Originally Posted by riechan
@2kaud: Sorry, can you please explain this line:
if (char *nl = strrchr(acct.name, '\n')) *nl = 0;
That is explained in the last line that 2kaud wrote:
Quote:
Originally Posted by 2kaud
Note that fgets reads the terminating new line so this needs to be removed.
You may find it somewhat more concise to write:
Code:
acct.name[strspn(acct.name, "\n")] = '\0';
The basic idea is to find (whether by using strrchr or strspn) the newline character, and then replace it with a null character.
Re: Assigning a value to struct variables?
Are you using c or c++? The code you are using looks like c but if you're using c++ then it would be better to use c++ strings and streams rather than the c library versions.
Code:
if (fp = fopen("acctinfo.txt", "r+")) {
if fopen succeeds, then a file pointer is returned otherwise it returns null. So this assigns the returned file pointer to fp and tests if it is non-zero.
Code:
if (fgets(acct.name, 60, fp) && fscanf(fp, "%19s\n%9s\n%f\n", acct.num, acct.pin, &acct.bal) == 3) {
fgets(..) will read the next line from the file and put a maximum of 59 chars into acct.name and null terminate it. fgets returns a pointer to acct.name on success or null on failure. fscanf returns the number of arguments actually assigned a value - which should be 3 in this case. So if fgets returns a non-null value and fscanf returns 3 then the test succeeds. Note that fscanf is only evaluated if fgets returns a non-null value.
Code:
if (char *nl = strrchr(acct.name, '\n')) *nl = 0;
strrchr searches from the end of acct.name until it finds a new line ('\n'). If it does find one then it returns a pointer to it otherwise it returns null. So this assigns the returned pointer from strrchr to nl and if this is non-null the test succeeds and then replaces the char pointed to by nl with a 0 which overwrites the \n and terminates the string.
If you are having trouble with pointers try these
http://www.learncpp.com/cpp-tutorial...n-to-pointers/
http://www.cplusplus.com/doc/tutorial/pointers/
Re: Assigning a value to struct variables?
I was told that using !feof() is a bad thing to do, so I guess I'll stick to my while statement? So the output is still the same. I really don't know what I'm doing wrong here, as to why the extra digits are appearing in the bal variable. I need to get the exact value since I'll be making computations using it...
I'm using C (in Turbo C) if it makes any difference, by the way.
Code:
#include <stdio.h>
#include <stdlib.h>
#define MAXAMT 999999.99
typedef struct Account{
char name[60];
char num[20];
char pin[10];
float bal;
} Account;
Account acct;
void loadAcct(){
char strbal[20];
FILE *fp;
fp = fp = fopen("/acctinfo.txt", "r+");
if (fp != NULL) {
while(fgets(acct.name, 60, fp) && 3 == fscanf(fp, "%19s%9s%f", acct.num, acct.pin, &acct.bal)) {
printf("%s\n%s\n%s\n%f\n", acct.name, acct.num, acct.pin, acct.bal);
}
} else {
printf("Account info not found.");
}
fclose(fp);
getch();
}
Re: Assigning a value to struct variables?
Quote:
Originally Posted by
riechan
I need to get the exact value since I'll be making computations using it...
Then you can't use double ot float.
This has been discussed many times here -- if you want accuracy, you need to use all integers or get a library of code that handles exact math. Doubles and floating point variables are by their very nature, inaccurate.
http://www.parashift.com/c++-faq/floating-pt-errs.html
Also, if you're using Turbo C, then the output we get will be different than the output that you will get when it comes to floating point values, since in all likelihood, others are using more modern compilers (Visual Studio or gcc). So comparing what 2kaud gets or laserlight gets in terms of that float variable is not an indicator of whether your program works or not.
I once had to maintain two bodies of code, one coded with Borland C++, the other with Visual Studio 6.0. The floating point calculations when applied to both compilers produced different numbers in the 4th or 5th decimal place.
Again, all of this is caused by inaccuracies of float and double. For float, there is no standard way that a compiler can represent that number. It could be IEEE or a home-grown version of characteristic/mantissa representation of that number (and I believe Turbo C even emulates floating point values via software, so that is another wrinkle).
Regards,
Paul McKenzie
Re: Assigning a value to struct variables?
Quote:
I need to get the exact value since I'll be making computations using it...
As has been said many times before on these threads, some decimal numbers can't be represented exactly as binary - the same way that 1/3 can't be represented exactly as a decimal. That's one reason why I used the %.2f format in the printf statement. However, consider storing bal as a double rather than a float. On my MSVS this gives a more accurate number representation. Also your fscanf format string is not correct. It will not work if there is more than 1 record in the file. Look at my fscanf format.
I've changed my program to use double rather than float and I'm now printing the whole balance rather than just 2dp.
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXAMT 999999.99
typedef struct Account{
char name[60];
char num[20];
char pin[10];
double bal;
} Account;
Account acct;
void loadAcct(){
FILE *fp;
if (fp = fopen("acctinfo.txt", "r+")) {
while (fgets(acct.name, 60, fp) && fscanf(fp, "%19s\n%9s\n%lf\n", acct.num, acct.pin, &acct.bal) == 3) {
if (char *nl = strrchr(acct.name, '\n')) *nl = 0;
printf("%s\n%s\n%s\n%lf\n", acct.name, acct.num, acct.pin, acct.bal);
}
} else {
printf("Account info not found.");
}
fclose(fp);
//getch();
}
int main()
{
loadAcct();
return 0;
}
Using input file data of
Code:
Rie Ishida
1234567890
123456
123456.78
code guru
1234567890
987654321
45.67
this now produces output of
Code:
Rie Ishida
1234567890
123456
123456.780000
code guru
1234567890
987654321
45.670000
On your turbo c system, try this program as it stands without changes and see what the output produces with the same data as I've used.
Re: Assigning a value to struct variables?
Quote:
Originally Posted by
2kaud
On your turbo c system, try this program as it stands without changes and see what the output produces with the same data as I've used.
I would also be interested in seeing the results.
I don't think that Turbo C used IEEE doubles (maybe I'm wrong), but I do remember that their floating point was either emulated, or if you had the 8087 chip, done using that FP coprocessor (which predates the IEEE standard used by Visual Studio / gcc).
Regards,
Paul McKenzie
1 Attachment(s)
Re: Assigning a value to struct variables?
@2kaud: Just made a couple of changes with the code. I used your test data and the results were all correct, surprisingly:
Attachment 31641
I'm thinking it's because I used float instead of double? And in this line of code, I was getting a 'Expression syntax' error:
Code:
if (char *nl; = strrchr(acct.name, '\n')) *nl = 0;
So, I changed it up to:
Code:
char *nl;
...
if (*nl = strrchr(acct.name, '\n')) {
*nl = 0;
}
And now I'm getting a nonportable pointer conversion/possibly incorrect assignment error. When I use this however:
Code:
i = strspn(acct.name, "\n");
acct.name[strspn(acct.name, "\n")] = '\0';
i = 0 and the acct.name variable is empty.
Re: Assigning a value to struct variables?
Quote:
if (char *nl; = strrchr(acct.name, '\n')) *nl = 0;
Sorry. That is c++ syntax. I forgot you're using c. In c++ you can define a variable within the if statement whereas you can't in c.:o
You need to use strcspn rather than strspn. strspn returns 0 if the first character of acct.name is not a \n which is not what you want!
Use this
Code:
while (fgets(acct.name, 60, fp) && fscanf(fp, "%19s\n%9s\n%lf\n", acct.num, acct.pin, &acct.bal) == 3) {
acct.name[strcspn(acct.name, "\n")] = 0;
printf("%s\n%s\n%s\n%lf\n", acct.name, acct.num, acct.pin, acct.bal);
}
I checked this using a c compiler and it compiles OK and produces the same result as above.
Quote:
So, I changed it up to:
Code:
char *nl;
...
if (*nl = strrchr(acct.name, '\n')) {
*nl = 0;
}
And now I'm getting a nonportable pointer conversion/possibly incorrect assignment error. When I use this however:
Thats because strrchr returns a pointer and you are assigning a pointer value to a char!
nl is a pointer to a memory location in which a char can be stored. *nl refers to the actual char stored at the memory location pointed to by nl. I know this can be confusing!
You need
Code:
char *nl;
...
if (nl = strrchr(acct.name, '\n')) {
*nl = 0;
}
Re: Assigning a value to struct variables?
Quote:
Originally Posted by
riechan
@2kaud: Just made a couple of changes with the code. I used your test data and the results were all correct, surprisingly:
You must also do one more thing, and that is to #include all of the appropriate headers that correspond with the functions you're calling.
For example, did you #include <string.h>? You're calling string functions, but I don't see that #include.
The reason why it is very important for a 'C' program to #include the headers is that a program can and will run differently if you leave them out. For 'C', if a function is undefined, 'C' defaults the return value to int, and that can be disastrous.
So next time, please post the headers you have included, since a lot of weird output for a 'C' program stems from not including the neessary header files (There was a thread that went on for days, with the issue being exactly that -- a 'C' program that didn't #include the headers, and the poster couldn't understand why they were getting the wrong output).
Regards,
Paul McKenzie
Re: Assigning a value to struct variables?
Quote:
Originally Posted by 2kaud
You need to use strcspn rather than strspn. strspn returns 0 if the first character of acct.name is not a \n which is not what you want!
Yeah, my bad.
Re: Assigning a value to struct variables?
I suppose I'll be using long integer for the time being, since floating point numbers have been very erratic. But, I'll revise the data types once I finish coding everything. I'll follow up on you guys with the finished code, I think.
I have a quick question though, when I tried to assign a value to acct.pin:
Both acct.pin and pina are string variables with a length of 10. I got an error: "Lvalue required"? I didn't get that error though when I tried using it with integer variables (acct.bal)
Re: Assigning a value to struct variables?
Quote:
Originally Posted by
riechan
I have a quick question though, when I tried to assign a value to acct.pin:
Both acct.pin and pina are string variables with a length of 10. I got an error: "Lvalue required"? I didn't get that error though when I tried using it with integer variables (acct.bal)
acct.pin is a fixed pointer (determined by the compiler) to a memory location where the data resides. So what you are doing isn't valid as you are trying to change the memory location to which acct.pin points. To copy the data from the char array pointed to by pina to the char array pointed to by acct.pin use
Code:
strcpy(acct.pin, pina);
Note that the memory storage allocated for acct.pin must be at least the number of characters copied from pina (not forgetting the terminating null!) - otherwise a buffer overflow occurs.
For more info on manipulating char arrays in c, have a look at
http://www.cplusplus.com/reference/cstring/
Quote:
I got an error: "Lvalue required"
An Lvalue is an expression that can be used on the left of an assignment. In the statement
a is the Lvalue and 3 is the Rvalue. If this was reversed
then here 3 is the Lvalue and a is the Rvalue. But 3 cannot be assigned a value so this is an error. In your example, acct.pin would be the Lvalue, but you can't assign to this hence the compiler error. This is why you often find if statements of the form
rather than
both perform the same test, but if the equality relational operator was mistyped as
then this would cause a compiler error as 3 is not a valid Lvalue. But the (probably incorrect) statement
is valid syntax and assigns a the value of 3 which is the value of the if condition. The condition is then always non-zero so the if statement always evalutes to true.
Re: Assigning a value to struct variables?
Quote:
Originally Posted by
riechan
I have a quick question though, when I tried to assign a value to acct.pin:
Both acct.pin and pina are string variables with a length of 10. I got an error: "Lvalue required"? I didn't get that error though when I tried using it with integer variables (acct.bal)
All 'C' books and materials make it a point that null-terminated char arrays are not the same as simple variables. Since they are arrays, you must use functions to manipulate them. Assignment and comparison of arrays cannot be done in C (and in C++) using "simple" operations such as "=" and "==". You must use the functions defined in <string.h> to manipulate null-terminated strings as one entity (as opposed to a single character at a time).
So are you using a 'C' book? If so, I suggest you read carefully the chapter on null-terminated char arrays, as that is a foundation of 'C' programming when it comes to strings.
Regards,
Paul McKenzie