I have a project of a phone book, I have a function to read the structure from a file, put it into an array of structure. So to make sure that it reads correctly I print it into an output file but the result of the output file,
0 (null) 6553280
I have a CSV file with the data like
Ahmed,Mohamed,26 Elhoreya Street,15,Alexandria,4876321,ahmed#gmail.com
Sarah,Zaki,7 Smouha,36,Alexandria,3974542,sarah#hotmail.com
The output is null, it doesn't (read/write) correctly, while using the debugger it shows that it's reading. Why?
int i;
int counter;
struct pb //main struct
{
char Firstname[25];
char Lastname[25];
char street[20];
int street_no ;
char city[15];
int number;
char email[50];
};
struct pb k[1000];
void read_str(struct queue *queue)
{
{
counter = 0 ;
FILE *read ;
char filename[40];
printf("Enter file name \n");
scanf("%s",&filename);
read=fopen(filename,"r");
if (read == NULL)
printf("Error");
else
while(!feof(read))
{
struct pb *n= malloc(sizeof(struct pb));
fscanf(read,"%[^,],%[^,],%[^,],%d,%[^,],%d,%s\n",
k[counter].Firstname, k[counter].Lastname,
k[counter].street, &k[counter].street_no,
k[counter].city, &k[counter].number, k[counter].email );
counter++;
}
fclose(read);
}
}
int main()
{
read_str(&k);
FILE *read ;
read=fopen("out.txt","w");
fprintf(read,"%s %s %s %d %s %d %s ",
k[counter].Firstname, k[counter].Lastname,
k[counter].street, k[counter].street_no, k[counter].city,
k[counter].number, k[counter].email );
fclose(read);
return 0 ;
}
I can at least at a first glance see that the value of the counter during fprintf in main function is one past the end of your valid structure array (because of counter++ after the fscanf), which means it is undefined.
Moreover, I think you want to run a loop to fprintf all the records (structs). But you didn't.
Your orderings of fscanf and fprintf format specifiers are inconsistent.
It is clear that your code is doing nothing useful in the main function.
Update
Minimally corrected code:
#include <stdio.h>
int counter;
struct pb //main struct
{
char Firstname[25];
char Lastname[25];
char street[20];
int street_no ;
char city[15];
int number;
char email[50];
};
struct pb k[1000];
void read_str()
{
FILE *fin;
char filename[40];
counter = 0 ;
printf("Enter file name \n");
scanf("%s",filename);
if((fin=fopen(filename,"r"))!=NULL)
{
while(!feof(fin))
{
fscanf(fin,"%[^,],%[^,],%[^,],%d,%[^,],%d,%s\n",k[counter].Firstname, k[counter].Lastname, k[counter].street, &k[counter].street_no, k[counter].city, &k[counter].number, k[counter].email);
++counter;
}
fclose(fin);
}
}
int main()
{
int i;
FILE *fout;
read_str();
if((fout=fopen("out.txt","w"))!=NULL)
{
for(i=0; i<counter; ++i)
{
fprintf(fout,"%s %s %d %s %s %s %d\n",
k[i].Firstname, k[i].Lastname, k[i].street_no,
k[i].street,k[i].city,k[i].email,k[i].number );
}
fclose(fout);
}
return 0 ;
}
N.B. There are still many caveats in this code.
In addition to not writing beyond the end of your array-of-structs when reading your data, there are several additional areas where you may want to revise the approach you have taken with your code.
First, unless there is a compelling reason to declare your data structure as a global variable, you should limit its scope to main() and pass the array-of-structs as a parameter to any functions that need access to the data. In addition, when dealing with constants in your program (e.g. max phonebook entries 1000), it is good practice to either define a constant (#define MAXE 1000) or preferably use an enum to define the constant, e.g.:
enum { MAXE = 1000 };
(An anonymous enum is fine.)
You can also simplify your life by creating a typedef to your struct as well which will make passing the array-of-structs as a parameter easier. For instance you can declare a typedef to your struct (either named or anonymous) as follows:
typedef struct {
char Firstname[25];
char Lastname[25];
char street[20];
int street_no ;
char city[15];
int number;
char email[50];
} pb;
This will allow a simple declaration in main(), e.g.:
pb k[MAXE] = {{{0},{0},{0},0,{0},0,{0}}};
While not required, it is also good practice to initialize all variables, (including your array-of-structs), when they are declared.
While in this instance, there is little difference between reading the data file with fscanf or using a line-oriented input function, you will generally find reading a line at a time with fgets or getline and then parsing the line into components with sscanf or simple pointers will provide a more flexible and robust input routine. Regardless whether you read with fscanf or read with fgets and parse with sscanf always check the returns of fscanf or sscanf to validate the number of successful conversions.
The benefit of using line-oriented input functions to read each line of text from your input file is it will eliminate the rigidity of the fscanf format-string from the actual read of the file and allow you to handle separating the values after the line has been successfully read into a buffer. An example of using fgets in your case could be:
/* read addresses from input file up to a maximum of MAXE
* addresses. updates 'idx' pointer to hold the number of
* addreses read from file and returns number read
*/
size_t read_str (pb (*k)[], size_t *idx, FILE *fp)
{
char tmp[MAXL] = {0};
while (*idx < MAXE && fgets (tmp, MAXL, fp)) {
// printf ("read[%zu]\n", *idx);
if (sscanf (tmp, " %24[^,],%24[^,],%19[^,],%d,%14[^,],%d,%49[^\n]",
(*k)[*idx].Firstname, (*k)[*idx].Lastname,
(*k)[*idx].street, &(*k)[*idx].street_no,
(*k)[*idx].city, &(*k)[*idx].number, (*k)[*idx].email) != 7) {
fprintf (stderr, "read_str() error: parse of line[%zu] failed.\n",
*idx);
break;
}
(*idx)++;
}
return *idx;
}
note also the return of the number of address entries read allowing you to gauge success/failure of the function as well as providing you with the number of entries read. The number of entries read (idx) is also passed as a pointer to the function making the number of entries available in the calling function (main() here) regardless of whether the return is assigned.
Beyond those initial issues, you will want to validate each action you take that has consequence for the continued operation of your code. (e.g. all file opens, reads, writes, etc...) Putting those pieces together and adding basic validation, and using line oriented input, another approach to your task could look like the following:
#include <stdio.h>
/* constants for max input line and max entries */
enum { MAXL = 256, MAXE = 1000 };
typedef struct {
char Firstname[25];
char Lastname[25];
char street[20];
int street_no ;
char city[15];
int number;
char email[50];
} pb;
size_t read_str (pb (*k)[], size_t *idx, FILE *fp);
void print_str_fmt (pb *k, size_t idx);
int print_str (pb *k, size_t idx, FILE *fp);
int main (int argc, char **argv) {
if (argc < 3) { /* validate input/output filenames given as arguments */
fprintf (stderr, "error: insufficient input, usage: %s infile outfile\n",
argv[0]);
return 1;
}
pb k[MAXE] = {{{0},{0},{0},0,{0},0,{0}}}; /* initialize variables */
size_t index = 0;
FILE *ifp, *ofp;
if (!(ifp = fopen (argv[1], "r"))) { /* validate input file open */
fprintf (stderr, "error: file open failed '%s'\n", argv[1]);
return 1;
}
if (!(ofp = fopen (argv[2], "w"))) { /* validate output file open */
fprintf (stderr, "error: file open failed '%s'\n", argv[2]);
return 1;
}
if (!read_str (&k, &index, ifp)) { /* validate entries read */
fprintf (stderr, "error: read_str - no addresses read\n");
return 1;
}
fclose (ifp); /* close input file */
printf ("The addresses are:\n\n");
print_str_fmt (k, index);
if (print_str (k, index, ofp)) { /* validate entries written */
fprintf (stderr, "error: print_str - no addresses read\n");
return 1;
}
fclose (ofp); /* close output file */
return 0;
}
/* read addresses from input file up to a maximum of MAXE
* addresses. updates 'idx' pointer to hold the number of
* addreses read from file and returns number read
*/
size_t read_str (pb (*k)[], size_t *idx, FILE *fp)
{
char tmp[MAXL] = {0};
while (*idx < MAXE && fgets (tmp, MAXL, fp)) {
// printf ("read[%zu]\n", *idx);
if (sscanf (tmp, " %24[^,],%24[^,],%19[^,],%d,%14[^,],%d,%49[^\n]",
(*k)[*idx].Firstname, (*k)[*idx].Lastname,
(*k)[*idx].street, &(*k)[*idx].street_no,
(*k)[*idx].city, &(*k)[*idx].number, (*k)[*idx].email) != 7) {
fprintf (stderr, "read_str() error: parse of line[%zu] failed.\n",
*idx);
break;
}
(*idx)++;
}
return *idx;
}
/* formatted print of addressbook to stdout */
void print_str_fmt (pb *k, size_t idx)
{
size_t i;
for (i = 0; i < idx; i++)
printf (" %s %s\n %s No. %d\n %s, %d\n %s\n\n",
k[i].Firstname, k[i].Lastname, k[i].street, k[i].street_no,
k[i].city, k[i].number, k[i].email);
}
int print_str (pb *k, size_t idx, FILE *fp)
{
size_t i;
for (i = 0; i < idx; i++)
if (fprintf (fp, "%s,%s,%s,%d,%s,%d,%s\n",
k[i].Firstname, k[i].Lastname, k[i].street, k[i].street_no,
k[i].city, k[i].number, k[i].email) < 0)
return 1;
return 0;
}
Compile
gcc -Wall -Wextra -O3 -o bin/readstructsscanf readstructsscanf.c
Test Input
$ cat ../dat/phonebook.txt
Ahmed,Mohamed,26 Elhoreya Street,15,Alexandria,4876321,ahmed#gmail.com
Sarah,Zaki,7 Smouha,36,Alexandria,3974542,sarah#hotmail.com
Use/Output
$ ./bin/readstructsscanf ../dat/phonebook.txt foo.txt
The addresses are:
Ahmed, Mohamed
26 Elhoreya Street No. 15
Alexandria, 4876321
ahmed#gmail.com
Sarah, Zaki
7 Smouha No. 36
Alexandria, 3974542
sarah#hotmail.com
Confirm Output File
$ diff ../dat/phonebook.txt foo.txt
$
As with all problems in C, there are usually many ways to approach a correct solution. Hopefully this will give you a few additional ideas on how to make your code more flexible and robust.
Related
my teacher asked me to make a program that can read employee's ID, name and salary from txt file, but I'm currently struggling with writing code that can read the txt in order.
#include<stdio.h>
typedef struct em{
char id[20];
char name[256];
float sal;
};
void read_file(em *a, int *i){
FILE *p;
*i=0;
char x[20],y[20],z[20];
bool isRead;
p=fopen("D:/--LMS--/PRF192/Assignment_File/A.txt","r");
if (p==NULL){
printf("File not found...");
} else {
fscanf(p,"%s %s %s",x,y,z);
while (fscanf(p,"%s %s %f",a[*i].id,a[*i].name,&a[*i].sal)!=EOF){
*i++; }
for (int t=1;t<=*i;t++){
printf("%s\n%s\n%f\n",a[*i].id,a[*i].name,a[*i].sal);
}
} printf("Finished");
}
main(){
em em[100];
int amount=0;
read_file(em,&amount);
}
It should output the file's data along with "Finished" as the final line.
File Data:
EmID EmName EmsalaryLevel
A001 EgsyPrub 3.4
A002 PattyEin 2.4
A003 TheodoreEly 4.5
While you have discovered the problem with *i++ incrementing the pointer-address instead of the value at the address held by the pointer (*i)++, you would benefit from simplifying things by separating what you need to accomplish into distinct operations.
First, don't use magic numbers in your code (except where absolutely required like with the scanf field-width modifier) and don't use hardcoded strings or filenames. Instead, If you need a constant, #define one (or more), or use a global enum to do the same thing. That way you have one single place at the top of your code to change things if needed and you don't have to go picking through your declarations or loop limits to change things.
In your case, you can simply #define the needed constants, and you pass the filename to read as an argument to your program (that's what your argument-count and argument-vector are for, e.g. int argc, char **argv) For example:
#include <stdio.h>
#define MAXID 20 /* don't use magic numbers in your code! */
#define MAXEM 100 /* if you need a constant, #define one (or more) */
#define MAXNM 256
#define MAXC 1024
...
typedef struct { /* struct for employee data */
char id[MAXID];
char name[MAXNM];
float sal;
} employee; /* (note: typedef name goes at end...) */
Now, looking at your data-file, you need to read two different types of lines of data. (1) a heading line with 3-categories that you call x, y, z (not descriptive, but we will run with it...), and (2) employee data consisting of and id, name, sal which you are currently storing in an array of struct (that's good!).
While the heading line could probably be a single line without being broken into x, y, z, you need some way to get that data back from your function. A simple way is to create a second typedef for a struct to hold x, y & z and you can make that available back in the caller the same way you do a (your array of employee data), e.g.
typedef struct { /* provide a struct for heading values */
char x[MAXID],y[MAXID],z[MAXID];
} heading;
You are performing Input Critical operations in read_file yet your return type is void? If there is any chance of failure in your function, you need to choose a meaningful return type that can indicate success/failure. While you are at it, why not return the number of employee records read instead of passing the pointer to i?
That way you can indicate failure with a return 0; and indicate success by returning the positive number of records read -- which can be assigned to amount back in the caller eliminating the need to monkey with incrementing the value held by the pointer i altogether. (and since it will be a count, a proper type would be size_t rather than int -- you won't have a negative count)
As mentioned in the comment, you generally want to attempt to open the file in the caller and pass an open FILE* pointer to your function as a parameter. That allows you to validate you have an open file before calling your read_file function. No need for the function call, if the file doesn't exist. Adding those considerations, you could write your read_file function as:
/* read heading and employee data from open file fp, returning
* the number of employee records on success, 0 on failure.
*/
size_t read_file (FILE *fp, heading *h, employee *a)
{
char buf[MAXC]; /* buffer to read each line */
size_t i = 0; /* employee record counter (not including heading) */
if (fgets (buf, MAXC, fp)) { /* read heading & validate */
if (sscanf (buf, "%19s %19s %19s", h->x, h->y, h->z) != 3) {
fputs ("error: invalid 1st line format.\n", stderr);
return 0;
}
}
while (i < MAXEM && fgets (buf, MAXC, fp)) { /* read each line */
if (sscanf (buf, "%19s %19s %f",
a[i].id, a[i].name, &a[i].sal) != 3) {
fprintf (stderr, "invalid format line %zu.\n", i);
return i;
}
i++; /* increment count only on successful parse */
}
return i; /* return number of employee records */
}
(note: how all line of data are read with fgets into buf before the individual values are parsed from each line. This ensures you consume an entire line of data with each input call. Note also, how the array bounds of each array are protect by using the field-width modifier to each conversion specifier used in sscanf and by including i < MAXEM in your read loop)
Opening your file in main(), passing the open file pointer along with a pointer to a heading struct and your array of employee data and assigning the return to amount allows you to call your function similar to:
if ((amount = read_file (fp, &h, em))) { /* validate records read */
(you can of course, do amount = read_file (fp, &h, em); first and then validate with if (amount) { -- it's up to you)
A complete main() that takes the filename to read as its argument (or reads from stdin by default if no argument is given) could be written as follows:
int main (int argc, char **argv) {
heading h = { .x = "" }; /* declare heading struct */
employee em[MAXEM] = {{ .id = "" }}; /* declare array of employees */
size_t amount = 0; /* counting types use size_t */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if ((amount = read_file (fp, &h, em))) { /* validate records read */
printf ("%-8s%-12s%s\n", h.x, h.y, h.z); /* output heading */
for (size_t i = 0; i < amount; i++) /* output employee recs */
printf ("%-8s%-12s%.1f\n", em[i].id, em[i].name, em[i].sal);
}
else /* otherwise throw error that read failed */
fputs ("error: no data read from file.\n", stderr);
}
(the formatting is handled by the field-width modifier again used with print to preserve your 8-character and 12-character field width for columns 1 & 2 from your data file.)
Putting it altogether you could do:
#include <stdio.h>
#define MAXID 20 /* don't use magic numbers in your code! */
#define MAXEM 100 /* if you need a constant, #define one (or more) */
#define MAXNM 256
#define MAXC 1024
typedef struct { /* provide a struct for heading values */
char x[MAXID],y[MAXID],z[MAXID];
} heading;
typedef struct { /* struct for employee data */
char id[MAXID];
char name[MAXNM];
float sal;
} employee; /* (note: typedef name goes at end...) */
/* read heading and employee data from open file fp, returning
* the number of employee records on success, 0 on failure.
*/
size_t read_file (FILE *fp, heading *h, employee *a)
{
char buf[MAXC]; /* buffer to read each line */
size_t i = 0; /* employee record counter (not including heading) */
if (fgets (buf, MAXC, fp)) { /* read heading & validate */
if (sscanf (buf, "%19s %19s %19s", h->x, h->y, h->z) != 3) {
fputs ("error: invalid 1st line format.\n", stderr);
return 0;
}
}
while (i < MAXEM && fgets (buf, MAXC, fp)) { /* read each line */
if (sscanf (buf, "%19s %19s %f",
a[i].id, a[i].name, &a[i].sal) != 3) {
fprintf (stderr, "invalid format line %zu.\n", i);
return i;
}
i++; /* increment count only on successful parse */
}
return i; /* return number of employee records */
}
int main (int argc, char **argv) {
heading h = { .x = "" }; /* declare heading struct */
employee em[MAXEM] = {{ .id = "" }}; /* declare array of employees */
size_t amount = 0; /* counting types use size_t */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
if ((amount = read_file (fp, &h, em))) { /* validate records read */
printf ("%-8s%-12s%s\n", h.x, h.y, h.z); /* output heading */
for (size_t i = 0; i < amount; i++) /* output employee recs */
printf ("%-8s%-12s%.1f\n", em[i].id, em[i].name, em[i].sal);
}
else /* otherwise throw error that read failed */
fputs ("error: no data read from file.\n", stderr);
}
Compiling
With gcc:
gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -O2 -o idnamesal idnamesal.c
With VS Developer's Command Prompt
cl /W3 /wd4996 /Ox /Feidnamesal /Tc idnamesal.c
Example Use/Output
Which when compiled and provided your input file as an argument, would produce the following output:
$ ./bin/idnamesal dat/emdata.txt
EmID EmName EmsalaryLevel
A001 EgsyPrub 3.4
A002 PattyEin 2.4
A003 TheodoreEly 4.5
(output on both Linux and Windows is the same)
Lastly, always compile with warnings enabled, and do not accept code until it compiles cleanly without warning. To enable warnings add -Wall -Wextra -pedantic to your gcc/clang compile string (also consider adding -Wshadow to warn on shadowed variables). For VS (cl.exe on windows), use /W3. Read and understand each warning -- then go fix it. They will identify any potential problems, and the exact line on which it occurs. You can learn a lot by listening to what your compiler is telling you.
There are many ways to put this read together, so don't take this as the only way. The key, regardless how you do it, is the validate every critical step in your program and always protect your array bounds from overrun. Doing that alone will save you no end of grief as you learn C.
There are two main issues that cause the code not to work properly:
Inside the first loop that reads from the file, you try to increase the value pointed to by i. However, you actually increase the value of i itself and then try to dereference it, which causes invalid memory access. In order to solve it, surround the dereferencing operation with parenthesis, so that it will be executed first:
(*i)++;
You forgot to use your new index variable, t, in the second loop for printing the data. Instead you just use the same index value (*i) for all of the iterations. You should also start your count from 0, same as the initial value of *i.
for (int t=0;t<*i;t++){
printf("%s\n%s\n%f\n",a[t].id,a[t].name,a[t].sal);
}
My code pulls data from one text file and then totals the points and enters it into a separate text file, so I would like the program to organize the teams and scores by total points prior to frpintf into the text file. So far the program pulls and runs the data and totals it out and fprintf just fine, should I use qsort to sort and print into the text file, and where in my code do I place it. Here is the text it is reading.
Indians 54 45 5
Twins 45 53 7
Tigers 43 59 8
White_Sox 35 64 9
Royals 30 69 3
Also I know there are no ties in the MLB lol just throwing in an additional variable.
Thanks.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int main(void)
{
struct records {
char filename;
char team[50];
int wins;
int tie;
int loss;
int points;
};
struct records roster;
FILE *ifp = NULL;
FILE *afd = NULL;
const int argv;
char filename2[64] = {0};
char filename[64] = {0};
int points;
int points2;
int total;
printf("\nPlease enter the the .txt file you would like to open: ");
scanf("%63s", filename);
printf("Opened file name %s",filename);
ifp = fopen(filename,"r");
if (ifp == NULL)
{
printf("Could not open");
printf("\nPlease enter the the .txt file you would like to open:");
scanf("%63s", filename);
printf("Opened file name %s",filename);
ifp = fopen(filename,"r");
}
printf("\nReading the file %s \n", filename);
while(fscanf(ifp, "%s %d %d%d" , roster.team, &roster.wins, &roster.loss,
&roster.tie) != EOF)
printf("%s Wins:%d Losses:%d ties:%d\n", roster.team, roster.wins,
roster.loss, roster.tie);
printf("\nWins are worth 2 points ties are worth 1 point and losses are
worth \nzero in overall league standings.");
printf("\nHere are the overall ALCentral Standings!\n");
ifp = fopen(filename, "r");
fopen(filename, "r"); while(fscanf(ifp, "%s %d %d %d", roster.team,
&roster.wins, &roster.loss, &roster.tie) != EOF)
printf("%s Wins:%d Losses:%d ties:%d Total league points:%d\n",
roster.team, roster.wins, roster.loss, roster.tie, (roster.wins * 2 +
roster.tie * 1), total);
printf("closing %s", filename);
fclose(ifp);
printf("\nPlease enter the the .txt file you would like to write to: ");
scanf("%63s", filename2);
printf("Opened file name %s", filename2);
afd = fopen(filename2, "a+");
if (afd == NULL)
{
printf("Could not open"); printf("\nPlease enter the the .txt file you
would like to open: ");
scanf("%63s", filename2);
printf("Opened file name %s", filename2);
afd = fopen(filename2,"a+");
}
ifp = fopen(filename,"r");
fopen(filename, "r");
points = roster.wins * 2;
points2 = roster.tie * 1;
total = points + points2;
while(fscanf(ifp, "%s %d %d %d", roster.team, &roster.wins, &roster.loss,
&roster.tie) != EOF)
fprintf(afd, "%s Wins:%d Losses:%d ties:%d total league points:%d\n",
roster.team, roster.wins, roster.loss, roster.tie, (roster.wins *2 +
roster.tie *1 ), total, filename2);
printf("\nYour stats have been recorded to the selected
file!\nClosing all open files! \nThanks for using the STAT-Master!
Have a great day!
fclose(afd);
fclose(ifp);
return 0;
}
Your logic is quite jumbled. If I understand what you are attempting, you want to read each teams wins, loss and tie record from your data file, and then compute the points that are then used to sort the teams into descending (or perhaps ascending) order and then output the "the overall ALCentral Standings" to either stdout or a file, or both.
Before starting let's talk about your definition of struct records inside of main(). While legal, you generally will want your struct declaration to be at file scope so that the struct type is available to any functions you write to help process the data in your code. Here, you must move the declaration outside of main() because the qsort compare function will need to know what the type struct records is. The compare function cannot be declared and defined in main() because C does not allow nested function declarations. So move your struct outside of main(), e.g.
#define MAXR 16 /* if you need a constant, #define one (or more) */
#define MAXC 64
#define MAXB 1024
typedef struct records {
char team[MAXC];
int wins,
loss,
tie,
points;
} record_t;
(note: using a typedef can make things more convenient)
To begin with, your multiple attempts to read the filename is awkward and never insures you actually have a file open. It just makes a couple of attempts and then effectively gives up validation and just blindly assumes there is a valid file stream to read and write to and presses ahead. This is a recipe for invoking Undefined Behavior.
When ever you do anything in C, and especially when you are dealing with user input or file operations, you must validate every step. You must know whether or not the file is open for reading before you attempt to read. (no matter how many times you attempt to open it) You must validate what you have read before you begin using the values in your code. You must validate the state of your input stream before you attempt your next read, and handle any characters that remain.
With that in mind you can prompt for the filename and attempt to open the filename provided in a continual loop until you validate the file is actually open, e.g.
/** helper function to empty stdin between inputs */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
...
FILE *fp = NULL; /* file pointer */
do { /* loop until valid filename given and file open */
printf("\nenter input filename: ");
if (scanf (" %63[^\n]", filename) != 1) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
empty_stdin(); /* remove '\n' and any add'l chars in input buffer */
fp = fopen (filename, "r"); /* open filename */
if (fp == NULL) /* validate file open for reading */
perror ("fopen-input");
} while (fp == NULL);
printf("Opened file name %s\n\n",filename);
(note: rather than using scanf for user input, fgets provides a better approach to user input and far fewer pitfalls that scanf, example below with roster)
Next, your understanding of how to collect the data in memory in order to sort it, is not evident from your post. When you want to sort a collection of team information, you must read all team information into memory before you can pass the information to qsort for sorting.
You have a struct that holds all of information for each team, you simply need to read each line (record) from your input file into an array or struct which can then easily be passed to qsort for sorting.
To use qsort you first must define a compare function that is used to qsort to order your data. The compare function has a specific declaration:
int compare (const void *a, const void *b);
Where each const void * parameter will be a pointer to one of the elements in your array of records. (in C a void pointer, e.g. void* is a generic pointer that can be assigned from, or to, any other pointer type without a cast -- that is why the compare function's declaration uses that type for the parameters) Your job in writing a compare function is simply to provide a type to the pointers (either by assignment or by explicit cast, your choice) and then a comparison between the values that you wish to sort by. For example, your compare on the points member of each struct could simply be:
/** qsort compare function (descending order of points) */
int compare (const void *a, const void *b)
{
const record_t *ta = a;
const record_t *tb = b;
return (ta->points < tb->points) - (ta->points > tb->points);
}
(where the (a < b) - (a > b) simply evaluates to -1, 0, 1 depending on the inequalites, e.g. if a = 4 and b = 3, you have (0) - (1) which equals -1 meaning a sorts before b)
All that remains is reading each teams data into your array and computing points and then passing your array to qsort.
To read your data into an array, read each line into a buffer, parse the data in the buffer into the individual values, validate that each of the individual values where parsed correctly, compute the points value for each team, increment your array index and then go read the next line. You could do something like the following using fgets to read each line of data:
record_t roster[MAXR] = {{ .team = "" }}; /* array to hold teams */
...
/* read up to MAXR team records from file */
while (ndx < MAXR && fgets (buf, MAXB, fp)) {
/* parse data from buffer filled, saving return */
int rtn = sscanf (buf, " %49s %d %d %d" , roster[ndx].team,
&roster[ndx].wins, &roster[ndx].loss,
&roster[ndx].tie);
if (rtn < 4) /* if less than 4 conversions, get next line */
continue;
/* compute points (2 * wins + ties) */
roster[ndx].points = roster[ndx].wins * 2 + roster[ndx].tie;
ndx++; /* increment index */
}
fclose (fp); /* close file */
(note: you can add a strlen() check of buf to determine if additional characters remain in the line unread -- that is left to you).
With all you data in your array of structs roster, all that remains is passing roster to qsort and then outputting your sorted data.
The following sorts the data and outputs the results to stdout. Writing the output to a file is left to you, but hint, you don't need both ifp and afp and you don't need filename and filename2 or points2, you are only dealing with one file/filename at a time. The sort and output is simple:
/* sort roster based on points (descending order) */
qsort (roster, ndx, sizeof *roster, compare);
/* outpout results */
printf ("Here are the overall ALCentral Standings!\n\n"
"Team Wins Loss Tie Points\n\n");
for (int i = 0; i < ndx; i++)
printf ("%-12s %4d %4d %4d %4d\n", roster[i].team,
roster[i].wins, roster[i].loss, roster[i].tie,
roster[i].points);
Putting it altogether in an example, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXR 16 /* if you need a constant, #define one (or more) */
#define MAXC 64
#define MAXB 1024
typedef struct records {
char team[MAXC];
int wins,
loss,
tie,
points;
} record_t;
/** helper function to empty stdin between inputs */
void empty_stdin()
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
/** qsort compare function (descending order of points) */
int compare (const void *a, const void *b)
{
const record_t *ta = a;
const record_t *tb = b;
return (ta->points < tb->points) - (ta->points > tb->points);
}
int main (void) {
int ndx = 0; /* index for roster array */
char buf[MAXB] = "", /* buffer for fgetrs */
filename[MAXC] = ""; /* filename to read */
record_t roster[MAXR] = {{ .team = "" }}; /* array to hold teams */
FILE *fp = NULL; /* file pointer */
do { /* loop until valid filename given and file open */
printf("\nenter input filename: ");
if (scanf (" %63[^\n]", filename) != 1) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
empty_stdin(); /* remove '\n' and any add'l chars in input buffer */
fp = fopen (filename, "r"); /* open filename */
if (fp == NULL) /* validate file open for reading */
perror ("fopen-input");
} while (fp == NULL);
printf("Opened file name %s\n\n",filename);
/* read up to MAXR team records from file */
while (ndx < MAXR && fgets (buf, MAXB, fp)) {
/* parse data from buffer filled, saving return */
int rtn = sscanf (buf, " %49s %d %d %d" , roster[ndx].team,
&roster[ndx].wins, &roster[ndx].loss,
&roster[ndx].tie);
if (rtn < 4) /* if less than 4 conversions, get next line */
continue;
/* compute points (2 * wins + ties) */
roster[ndx].points = roster[ndx].wins * 2 + roster[ndx].tie;
ndx++; /* increment index */
}
fclose (fp); /* close file */
/* sort roster based on points (descending order) */
qsort (roster, ndx, sizeof *roster, compare);
/* outpout results */
printf ("Here are the overall ALCentral Standings!\n\n"
"Team Wins Loss Tie Points\n\n");
for (int i = 0; i < ndx; i++)
printf ("%-12s %4d %4d %4d %4d\n", roster[i].team,
roster[i].wins, roster[i].loss, roster[i].tie,
roster[i].points);
return 0;
}
Example Input File
The file is provided as given, with blank lines in between records.
$ cat dat/teams.txt
Indians 54 45 5
Twins 45 53 7
Tigers 43 59 8
White_Sox 35 64 9
Royals 30 69 3
Example Use/Output
$ ./bin/qsortstrcmp
enter input filename: dat/teams.txt
Opened file name dat/teams.txt
Here are the overall ALCentral Standings!
Team Wins Loss Tie Points
Indians 54 45 5 113
Twins 45 53 7 97
Tigers 43 59 8 94
White_Sox 35 64 9 79
Royals 30 69 3 63
Look things over and let me know if you have further questions.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
this code works for single word counts and it differentiate between words with punctuation words with upper lower case. Is there an easy way around to make this code work for pairs as well instead of single words? like I need to print the occurrence of every pair of words in a text file.
Your help is much appreciated,
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
FILE* f = fopen (argv[1], "r");
char buffer[10000];
if (argc != 2)
{
fprintf(stderr, "Usage: %s file\n", argv[0]);
}
fclose(f);
snprintf(buffer, sizeof(buffer), "tr -cs '[:punct:][a-z][A-Z]' '[\\n*]' < %s |"
" sort | uniq -c | sort -n", argv[1]);
return(system(buffer));
}
Example input
The Cat Sat On The Mat
Output
(The Cat, The Sat, The On, The The, The Mat, Cat The, Cat Sat, Cat On, for 30 pairs)
It seems inconceivable that the purpose of your assignment determining the frequency of word-pairs in a file would be to have you wrap a piped-string of shell utilities in a system call. What does that possibly teach you about C? That a system function exists that allows shell access? Well, it does, and you can, lesson done, nothing learned.
It seems far more likely that the intent was for you to understand the use of structures to hold collections of related data in a single object, or at the minimum array or pointer indexing to check for pairs in adjacent words within a file. Of the 2 normal approaches, use of a struct, or index arithmetic, the use of a struct is far more beneficial. Something simple to hold a pair of words and the frequency that pair is seen is all you need. e.g.:
enum { MAXC = 32, MAXP = 100 };
typedef struct {
char w1[MAXC];
char w2[MAXC];
size_t freq;
} wordpair;
(note, the enum simply defines the constants MAXC (32) and MAXP (100) for maximum characters per-word, and maximum pairs to record. You could use two #define statements to the same end)
You can declare an array of the wordpair struct which will hold a pair or words w1 and w2 and how many time that pair is seen in freq. The array of struct can be treated like any other array, sorted, etc..
To analyze the file, you simply need to read the first two words into the first struct, save a pointer to the second word, and then read each remaining word that remains in the file comparing whether the pair formed by the pointer and the new word read already exists (if so simply update the number of times seen), and if it doesn't exist, add a new pair updating the pointer to point to the new word read, and repeat.
Below is a short example that will check the pair occurrence for the words in all filenames given as arguments on the command line (e.g. ./progname file1 file2 ...). If no file is given, the code will read from stdin by default.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum { MAXC = 32, MAXP = 100 };
typedef struct {
char w1[MAXC];
char w2[MAXC];
size_t freq;
} wordpair;
size_t get_pair_freq (wordpair *words, FILE *fp);
int compare (const void *a, const void *b);
int main (int argc, char **argv) {
/* initialize variables & open file or stdin for seening */
wordpair words[MAXP] = {{"", "", 0}};
size_t i, idx = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) {
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* read from file given, or from stdin (default) */
idx = get_pair_freq (words, stdin);
/* read each remaining file given on command line */
for (i = 2; i < (size_t)argc; i++)
{ if (fp && fp != stdin) { fclose (fp); fp = NULL; }
/* open file for reading */
if (!(fp = fopen (argv[i], "r"))) {
fprintf (stderr, "error: file open failed '%s'.\n",
argv[i]);
continue;
}
/* check 'idx' against MAXP */
if ((idx += get_pair_freq (words, fp)) == MAXP)
break;
}
if (fp && fp != stdin) fclose (fp);
/* sort words alphabetically */
qsort (words, idx, sizeof *words, compare);
/* output the frequency of word pairs */
printf ("\nthe occurrence of words pairs are:\n\n");
for (i = 0; i < idx; i++) {
char pair[MAXC * 2] = "";
sprintf (pair, "%s:%s", words[i].w1, words[i].w2);
printf (" %-32s : %zu\n", pair, words[i].freq);
}
return 0;
}
size_t get_pair_freq (wordpair *pairs, FILE *fp)
{
char w1[MAXC] = "", w2[MAXC] = "";
char *fmt1 = " %32[^ ,.\t\n]%*c";
char *fmt2 = " %32[^ ,.\t\n]%*[^A-Za-z0-9]%32[^ ,.\t\n]%*c";
char *w1p;
int nw = 0;
size_t i, idx = 0;
/* read 1st 2 words into pair, update index 'idx' */
if (idx == 0) {
if ((nw = fscanf (fp, fmt2, w1, w2)) == 2) {
strcpy (pairs[idx].w1, w1);
strcpy (pairs[idx].w2, w2);
pairs[idx].freq++;
w1p = pairs[idx].w2; /* save pointer to w2 for next w1 */
idx++;
}
else {
if (!nw) fprintf (stderr, "error: file read error.\n");
return idx;
}
}
/* read each word in file into w2 */
while (fscanf (fp, fmt1, w2) == 1) {
/* check against all pairs in struct */
for (i = 0; i < idx; i++) {
/* check if pair already exists */
if (strcmp (pairs[i].w1, w1p) == 0 &&
strcmp (pairs[i].w2, w2) == 0) {
pairs[i].freq++; /* update frequency for pair */
goto skipdup; /* skip adding duplicate pair */
}
} /* add new pair, update pairs[*idx].freq */
strcpy (pairs[idx].w1, w1p);
strcpy (pairs[idx].w2, w2);
pairs[idx].freq++;
w1p = pairs[idx].w2;
idx++;
skipdup:
if (idx == MAXP) { /* check 'idx' against MAXP */
fprintf (stderr, "warning: MAXP words exceeded.\n");
break;
}
}
return idx;
}
/* qsort compare funciton */
int compare (const void *a, const void *b)
{
return (strcmp (((wordpair *)a)->w1, ((wordpair *)b)->w1));
}
Use/Output
Given your example of "Hi how are you are you.", it produces the desired results (in sorted order according to your LOCALE).
$ echo "Hi how are you are you." | ./bin/file_word_pairs
the occurrence of words pairs are:
Hi:how : 1
are:you : 2
how:are : 1
you:are : 1
(there is no requirement that you sort the results, but it makes lookup/confirmation a lot easier with longer files)
Removing qsort
$ echo "Hi how are you are you." | ./bin/file_word_pairs
the occurrence of words pairs are:
Hi:how : 1
how:are : 1
are:you : 2
you:are : 1
While you are free to attempt to use your system version, why not take the time to learn how to approach the problem in C. If you want to learn how to do it through a system call, take a Linux course, as doing it in that manner has very little to do with C.
Look it over, lookup the functions that are new to you in the man pages and then ask about anything you don't understand thereafter.
got some code here that won't compile correctly because it is saying that my pointer is already null when i am testing for a not null expression in my main function. here is the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCODE 53
#define MAXMESSAGE 256
void getCode(char *codeIn, char *filename) {
FILE *codeFile;
/* Open the file with the code */
codeFile = fopen(filename, "r");
if (codeFile == NULL) {
printf("Error opening the code file - program terminated\n");
exit(1);
}
/* Read the first (and assumed only) line from the file */
fgets(codeIn, MAXCODE, codeFile);
/* Terminate the string with /0 */
codeIn[MAXCODE] = '\0';
/* Close the file */
fclose(codeFile);
return;
}
int getMessage(int *message, char *filename) {
FILE *messageFile;
int counter = 0;
/* Open the file with the message */
messageFile = fopen(filename, "r");
if (messageFile == NULL) {
printf("Error opening the message file - program terminated\n");
exit(1);
}
/* Read one number at a time from the file and store it */
while (!feof (messageFile))
{
fscanf (messageFile, "%d", (message+counter));
counter++;
}
/* Close the file */
fclose(messageFile);
return (counter);
}
void sortMessage(int *message, int size) {
int i, j, temp;
for (i=0; i<size-1; i++) {
for (j=i; j<size; j++) {
if (message[i]>message[j]) {
temp = message[i];
message[i] = message[j];
message[j] = temp;
}
}
}
return;
}
void decodeMessage(char *codeIn, int *message, int size) {
FILE *outputFile;
int i = 0;
/* Open the output file */
outputFile = fopen("csis.txt", "w");
if (outputFile == NULL) {
printf("Error opening the output file - program terminated\n");
exit(1);
}
for (i=0; i< size; i++) {
fprintf(outputFile, "%c", codeIn[message[i]%100]);
printf("%c", codeIn[message[i]%100]);
}
printf("\n");
/* Close the file */
fclose(outputFile);
return;
}
int main(int argc, char *argv[])
{
char code[MAXCODE];
int msg[MAXMESSAGE];
int msgSize;
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
}
getCode(code, argv[1]);
msgSize = getMessage(msg, argv[2]);
sortMessage(msg, msgSize);
decodeMessage(code, msg, msgSize);
return;
}
So basically my code is using two files called codefile.txt and msgfile.txt to decode the secret message and write the decoded sequence to a new text file called csis.
As woolstar pointed out in the comments, you don't need to NUL terminate your codeIn array following fgets, because fgets will do that for you. In fact, this constitutes an overflow which we can best see by considering what happens when MAXCODE is 1: codeIn contains only one element: codeIn[0], and accessing codeIn[1] is an error.
Similarly, since MAXCODE is 53 and that's how many elements pointed to by codeIn, codeIn[message[i]%100] is suspicious because there's a potential for message[i]%100 to be an invalid index. While we're on this note, it might be wise to make message[i] an unsigned int so that it can't be negative. The format specifier (for printf and scanf) corresponding to unsigned int is %u.
while ( !feof(messageFile) ) is wrong because the EOF flag isn't set until an attempt is made at reading. Between attempting to read and your EOF test, however, you've incremented counter which means you've counted one too many items. Perhaps your loop should look like this:
while (fscanf(messageFile, "%d", (message+counter)) == 1)
{
counter++;
}
Note that this code assumes you've chosen to keep message[i] as an int. If you've chosen to use unsigned int instead, of course you'll want to use the %u format specifier.
You can probably see that feof is mostly superfluous... You can usually test for erroneous reads by checking the return value. Try to avoid feof in the future.
Your main function has a return type of int, yet at the end of it you have a return; statement which doesn't return an int value. Remove that. It's probably causing errors during compilation.
Presumably, when argv != 3 you want to return from main so you don't end up processing invalid arguments... Make sure you return an int value, e.g.
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
return 0;
}
/*Project 1
Student records
1. Read the file with the records
2. store them
3. sort them
4. output them
ex. input and output (SORTED by student ID
2040003 AAAA BBBBBBBBB ComputerScience 3.45
2040002 AAA CCC ElectricalEngineering 3.01
2040005 AAAAAAAAAAAAAAAAA BBB ComputerScience 3.60
2040002,AAA,CCC,ElectricalEngineering,3.01
2040003,AAAA,BBBBBBBBB,ComputerScience,3.45
2040005,AAAAAAAAAAAAAAAAA,BBB,ComputerScience,3.60
char* name = malloc(256*sizeof(char));
*/
int main()
{
typedef struct StudentRecords
{
int StudentID; //must be of size 7 between 1000000 and 9999999
char *Firstname; //= MALLOC(256*sizeof(char)); // must be any length and allocate memory dynamically.
char *Lastname; //= MALLOC(256*sizeof(char));
char *Department; //= MALLOC(256*sizeof(char));
float GPA; // must be between 0 and 4
} STUDENTRECORDS;
/*
First job is read the file
*/
//set variables
int i=0;
char filecontent, file_name[100];
FILE *fp;
STUDENTRECORDS StudentRecords[300];
STUDENTRECORDS a[300];
int size =0;
printf("Enter directory of file\n"); // instructs user to enter directory of file
gets(file_name); //prompt use
fp = fopen(file_name,"r"); //opens the file "r" is read mode for fopen()
// here is a check to see if fp is empty and throw an error if so
if (fp == NULL)
{
perror("Could not open file\n");
exit(EXIT_FAILURE);
}
printf("The contents of %s file are :\n", file_name); // just prints the file name (file_name) you are prompted for
// here is where the printing of contents actually occurs
while ((filecontent = fgetc(fp)) != EOF) // I think EOF is end of feed here, not 100%
{
printf("%c",filecontent);
}
//I thought this line was to figure out how many lines are in the text, but it isnt working.
while (!feof(fp))
{
read(StudentRecords, i, fp);
i++;
}
//because the while statement isnt working, Ive elected to setting size to 3 in order to continue coding.
size = i = 3;
printf("Size = %d\n", size);
//I thought this essentially put the files contents into
for (i = 0; i < size; ++i)
fscanf(fp, "%d %s %s %s %f\n", &StudentRecords[i].StudentID, &StudentRecords[i].Firstname, &StudentRecords[i].Lastname, &StudentRecords[i].Department, &StudentRecords[i].GPA);
for (i = 0; i < size; ++i)
printf("%s", StudentRecords[i]);
//printf("%d %s %s %s %f/n", &StudentRecords[i].StudentID, &StudentRecords[i].Firstname, &StudentRecords[i].Lastname, &StudentRecords[i].Department, &StudentRecords[i].GPA);
for (i = 0; i < size; ++i)
fscanf(fp, "%d %s %s %s %f\n", &a[i].StudentID, &a[i].Firstname, &a[i].Lastname, &a[i].Department, &a[i].GPA);
for (i = 0; i < size; ++i)
printf("%s", a[i]);
//printf("%d %s %s %s %f/n", &a[i].StudentID, &a[i].Firstname, &a[i].Lastname, &a[i].Department, &a[i].GPA);
// fclose() must follow an fopen()
fclose(fp);
//printf("%g", &StudentRecords);
// return code
return 0;
}
How do I add information into a struct and print it or use it? This is what
i have so far. I've tried many different things and to no avail. I think the problem is with my initializing my struct for use. I can't get it right. I've tried searching for a solution, but each one is different and don't explain much.
Thanks for any suggestions.
Please find example code for reading content from file and storing it in structure also for this example have only take 5 student data entry(you can change as you wish) And on which criteria you want to do sorting? So i leave sorting on you.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_ENTRY 5
typedef struct StudentRecords
{
int StudentID; //must be of size 7 between 1000000 and 9999999
char *Firstname; //= MALLOC(256*sizeof(char)); // must be any length and allocate memory dynamically.
char *Lastname; //= MALLOC(256*sizeof(char));
char *Department; //= MALLOC(256*sizeof(char));
float GPA; // must be between 0 and 4
} STUDENTRECORDS;
int main()
{
/*
First job is read the file
*/
//set variables
int i=0;
char filecontent, file_name[100];
FILE *fp;
STUDENTRECORDS StudentRecords[MAX_ENTRY];
for(i=0;i<MAX_ENTRY;i++)
{
StudentRecords[i].Firstname = malloc(sizeof(char)*256);
StudentRecords[i].Lastname = malloc(sizeof(char)*256);
StudentRecords[i].Department = malloc(sizeof(char)*256);
}
printf("Enter directory of file\n"); // instructs user to enter directory of file
gets(file_name); //prompt use
fp = fopen(file_name,"r"); //opens the file "r" is read mode for fopen()
// here is a check to see if fp is empty and throw an error if so
if (fp == NULL)
{
perror("Could not open file\n");
//exit(EXIT_FAILURE);
}
i=0;
while(EOF!=fscanf(fp, "%d %s %s %s %f\n", &StudentRecords[i].StudentID, StudentRecords[i].Firstname, StudentRecords[i].Lastname, StudentRecords[i].Department, &StudentRecords[i].GPA))
{
printf("%d %s %s %s %f\n", StudentRecords[i].StudentID, StudentRecords[i].Firstname, StudentRecords[i].Lastname, StudentRecords[i].Department, StudentRecords[i].GPA);
i++;
}
// fclose() must follow an fopen()
fclose(fp);
return 0;
}
Note: never forgot to free string which allocated by malloc after it's use.
A few comments, and some suggestions:
Was it your lecturer who said to use a linked-list? If so.. you really should do that otherwise you'll lose marks for failing to meet the spec.
EOF is 'End Of File'. feof() tells you if the stream pointer passed to it has hit EOF already.
Your while loop to print the contents is inefficient. Rather than reading every. single. character. in. the. file., you should read the entire file (or at least, large chunks thereof, let's not assume infinite memory), fclose() the stream and then operate on the read-in file.
Also, this sort of exercise lends itself very well to fixed-size record
Omitting error handling, variable declarations, structures and
using some pseudocode:
stat("/path/to/file", &statbuf)
inputfd = fopen("/path/to/file", r);
/* assuming that we only have a small file... */
contents = calloc(statbuf.st_size * sizeof(char));
/* read it all in, in one big chunk */
fread(contents, statbuf.st_size, 1, inputfd);
fclose(inputfd);
/* Now you can operate on it however you like */
bytesleft = statbuf.st_size;
/*
* this might need to go at the top of your block, depends on if you
* have enabled C99
*/
char eachline[MAXLINELENGTH];
int n = 0;
while (bytesleft > 0) {
add_new_list_element(mylist);
bzero(eachline, MAXLINELENTH);
memccpy(&eachline, contents[n], '\n', MAXLINELENGTH);
bytesleft -= sizeof(eachline);
nread = sscanf(start, "USE YOUR FORMAT STRING HERE", [variable list]);
if (nread < 0)
/* handle EOF, remember to make use of errno */
}
call_my_sort_function(mylist);
for (; thiselement != NULL; thiselement = thiselement->next)
print_salient_field_values(thiselement);