f

[File Handling] fread(), fseek() and text file

```Hi there. I have some questions about C programming concepts and solutions =
Yes, I am doing exercise for one very important exam in C programming. It i=
s very important for=20
me to pass this exam. Thats true. My English is poor to describe how import=
ant that is.
I desperately need a help to finish my example.

- NO I don=E2=80=99t want and I DON=E2=80=99t expect that someone do it for=
me.
- I will do it, but I need some help in sense of directions how to solve so=
me problems=20
- when I say =E2=80=9Cdirections=E2=80=9D, I mean I have some ideas and sol=
utions but I am not sure are they good=20
- sometimes I find solutions but I don=E2=80=99t understand 100% why it wor=
ks
- my exam example is cool and I like it and I love it and I am happy to wor=
k on it

On the other side, I need and I want and I will understand some concepts in=
C programming
and how it works. I am not satisfy to pass exam without understanding some =
issues. Yes, I have
a lot of books, video tutorials and so on, but I need some live person with=
C programming experience
to ask some questions and I will appreciate it a lot. On the other side, so=
me newbies they read this will also learn something I hope so.

---

One part of my exercise needs to read some text file. This text file looks =
like this:

* This is a comment
R1 0 1 (100/1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000)

My task is to make a program to read this file, to avoid comments if it hav=
e comments. The comments begin with the * sign. Then to sort this content a=
nd print it out on the screen on this way:

0 - R1(100/1) - 1
1 - C0(1/1000000) - 2
2 - L1(47/1000) - 3

After that I have to write code to do some calculations. This calculations =
are for now not important.

# important: one line can have max 128 characters and lines with i.e. "R1 0=
1 (100/1)" you can max. 19
---

Okey, I am doing step by step.=20

(1) for avoiding comments I have no idea, I am thinkging 7 days how to solv=
e it. Maybe with fseek() function but ...

(2) I have made experiment to first input a text file and to print it out w=
ithout comments and it works fine with binary file!=20

It looks like this:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FILENAME "netlist.txt"

typedef struct=20
{
char component[4];
unsigned a_node;
unsigned b_node;
char value[20];=09
}Components;

long lSize =3D 0;

int main()
{
size_t kurton;
FILE *pFile =3D fopen(FILENAME, "r");
=20
// obtain a file size
fseek(pFile, 0L, SEEK_END);
lSize =3D ftell (pFile);
rewind (pFile);

Components *temp =3D (Components*)malloc(sizeof(Components));

if(pFile)
{
while((kurton =3D fread(temp, sizeof(Components), lSize, pFile)) > 0)
{
printf("%s %u %u %s\n", temp->component, temp->a_node, temp->b_node, =
temp->value);
}
}
fclose(pFile);
free(temp);
temp =3D NULL;
return 0;
}

---

Of course this code will not be in main() function and it is not needed to =
be printed out the content of input file just sort (for sort I have idea ho=
w to do it).

But, when it commes on the console I got the result:

> ./test

R1 0 1 (100/1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000):?? 673198368 791687217 1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000):??

Here I need to solutions and help with some suggestions:

-1- how to avoid this part=20

:?? 673198368 791687217 1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000):??

because I need just to have:

R1 0 1 (100/1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000)

-2- how to handle with comments. With fgetc() I can identify a character wi=
th * but how to put instructions for fread() function NOT to read the whole=
line which begins with *.

ormations how to solve this problems.

Thanks guys. ;)

```
 0
Dexterr
12/16/2016 9:10:08 AM
comp.lang.c 30656 articles. 5 followers. spinoza1111 (3246) is leader.

30 Replies
812 Views

Similar Articles

[PageSpeed] 20

```[Text re-flowed, big time!]

On 16/12/16 09:10, Dexterr wrote:

> One part of my exercise needs to read some text file.
> This text file looks like this:

Your line lengths are completely screwed, and they confuse the hell out
of Thunderbird. Please fix them. Here is a sample of what you are
actually posting:

+++++++++++++++++++++++
Hi there. I have some questions about C programming concepts and solutions =
Yes, I am doing exercise for one very important exam in C programming. It i=
s very important for=20
+++++++++++++++++++++++

Can you see how totally broken that is?

> * This is a comment
> R1 0 1 (100/1)
> C0 1 2 (1/1000000)
> L1 2 3 (47/1000)

Text file. Got it.

> My task is to make a program to read this file, to avoid
> * sign. Then to sort this content and print it out on the
> screen on this way:
>
> 0 - R1(100/1) - 1
> 1 - C0(1/1000000) - 2
> 2 - L1(47/1000) - 3
>
> After that I have to write code to do some calculations.
> This calculations are for now not important.
>
> # important: one line can have max 128 characters and
> lines with i.e. "R1 0 1 (100/1)" you can max. 19
> ---
>
> Okey, I am doing step by step.
>
> (1) for avoiding comments I have no idea, I am thinkging 7
> days how to solve it. Maybe with fseek() function but ...

Well, that bit at least is simple, surely? You have a text file, so
you'll be reading it with an fgets loop. If the first character is an
asterisk, it's a comment, so you just don't bother to process that line:

while(fgets(line, sizeof line, fp) != NULL)
{
if(line[0] != '*') /* skip comment lines */
{
you have some data to process

>
> (2) I have made experiment to first input a text file and to
> print it out without comments and it works fine with binary file!

You said your input is a text file, so it seems to me that it hardly
matters whether or not it works with a binary file (and if it /does/
work with a binary file, it's probably not going to work with a text file).

In fact the distinction between "binary file" and "text file" in C is
purely to do with how you open it - as a binary stream, or a text
stream. But in practice, a text file consists of readable text
characters, typically [a-z], [A-Z], [0-9], punctuation, and whitespace.
If there are arbitrary byte values in the file, such as might be used in
the object representation of an int or a double, then "text file" is
really a misnomer.

> It looks like this:
>
> #include <stdio.h>
> #include <string.h>
> #include <stdlib.h>
>
> #define FILENAME "netlist.txt"

Although honouring file extensions is by no means mandatory, the name
does again suggest a text file, not a binary file.

>
> typedef struct
> {
>   char component[4];
>   unsigned a_node;
>   unsigned b_node;
>   char value[20];
> }Components;
>
> long lSize = 0;
>
> int main()

Better: int main(void)

> {
>   size_t kurton;
>   FILE *pFile = fopen(FILENAME, "r");

What if the file fails to open? How will your program avoid crashing?
(Hint: as it stands, it won't.)

if(pFile != NULL)
{
proceed
}
else
{
tell the user what went wrong
}

This pattern can be nested. If it nests too deeply, write some functions.

>
>   // obtain a file size
>   fseek(pFile, 0L, SEEK_END);

Why do you need that? And what makes you think fseek is the right tool
for determining file size?

>   lSize = ftell (pFile);
>   rewind (pFile);

This is completely the wrong approach. You don't need the file size at
all! And if you did, that isn't the right way to get it.

>   Components *temp = (Components*)malloc(sizeof(Components));

Components *temp = malloc(sizeof *temp);

Shorter, clearer, more robust in the face of later maintenance.

>
>   if(pFile)

It's a bit late for that. You should do it immediately after opening the
file.

But you /do/ need this:

if(temp != NULL)

And by the way, temp is a crap name.

>   {
>     while((kurton = fread(temp, sizeof(Components), lSize, pFile)) > 0)

It's a text file, right? So why are you reading text descriptions of
numbers into numeric fields? The results will be meaningless.

Use fgets() to retrieve the line:

char line[130] = ""; /* your limit of 128,
+ 1 for newline,
+ 1 for '\0' */

while(fgets(line, sizeof line, pFile) != NULL)
{
if(line[0] != '*')
{

And now you have to pick apart the fields in that string. It
seems that, on this occasion, your data are separated by whitespace, so
it's easy - you can just use strtok. But fread-ing into a struct is
never going to work.

>     {
>       printf("%s %u %u %s\n", temp->component, temp->a_node,
temp->b_node, temp->value);

The most likely outcome of this is, I think, a print of the whole
record, optionally followed by garbage. A crash is also possible, however.

>> ./test
>
> R1 0 1 (100/1)
> C0 1 2 (1/1000000)
> L1 2 3 (47/1000):?? 673198368 791687217 1)

Prediction confirmed.

What you should be doing is picking apart the textual data using
(perhaps) strtok, converting the numbers you need to convert using
strtol or strtoul, and then populating your struct using the results of
those conversions. Until you have code to do that, your printf is never
going to work.

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/16/2016 9:59:03 AM
```
> It's a text file, right? So why are you reading text descriptions of
> numbers into numeric fields? The results will be meaningless.
>
> Use fgets() to retrieve the line:
>
>    char line[130] = ""; /* your limit of 128,
>                            + 1 for newline,
>                            + 1 for '\0' */
>
>    while(fgets(line, sizeof line, pFile) != NULL)
>    {
>      if(line[0] != '*')
>      {
>

Mr Richard, thanks for your response. I am very grateful on your help.

For instance in the text file above we can have more comments. Comments can be only in one line but that means we can have one comment in two or three lines and in front of each
there is '*' sign.

for instance

* This is comment
* This is second line of the same comment
* and this is the last line of the whole comment
R1 0 1 (100/1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000)

--
So, if we have:

char line[130] = ""; /* your limit of 128,
>                            + 1 for newline,
>                            + 1 for '\0' */
>
>    while(fgets(line, sizeof line, pFile) != NULL)
>    {
>      if(line[0] != '*')  ->>>> this part is the problem
>      {
>

- >> if(line[0] != '*') - suppose that we have the comment only in the first line.
What to do when we have more lines of comments and each begin with '*' ?

This make a confusion and have no idea how to solve it.

Thanks a lot.

```
 0
Dexterr
12/16/2016 1:28:14 PM
```On 16/12/16 13:28, Dexterr wrote:
>
>
>> It's a text file, right? So why are you reading text descriptions of
>> numbers into numeric fields? The results will be meaningless.
>>
>> Use fgets() to retrieve the line:
>>
>>    char line[130] = ""; /* your limit of 128,
>>                            + 1 for newline,
>>                            + 1 for '\0' */
>>
>>    while(fgets(line, sizeof line, pFile) != NULL)
>>    {
>>      if(line[0] != '*')
>>      {
>>
>
> Mr Richard, thanks for your response. I am very grateful on your help.
>
> For instance in the text file above we can have more comments. Comments can be only in one line but that means we can have one comment in two or three lines and in front of each
> there is '*' sign.
>
> for instance
>
> * This is comment
> * This is second line of the same comment
> * and this is the last line of the whole comment
> R1 0 1 (100/1)
> C0 1 2 (1/1000000)
> L1 2 3 (47/1000)
>
> --
> So, if we have:
>
> char line[130] = ""; /* your limit of 128,
>>                            + 1 for newline,
>>                            + 1 for '\0' */
>>
>>    while(fgets(line, sizeof line, pFile) != NULL)
>>    {
>>      if(line[0] != '*')  ->>>> this part is the problem

No, it isn't. It's the solution to your comment problem.

>>      {
>>
>
> - >> if(line[0] != '*') - suppose that we have the comment only in the first line.

If only the first line is a comment, only the first line will be ignored.

> What to do when we have more lines of comments and each begin with '*' ?

Each line that starts with a '*' will be ignored.

> This make a confusion and have no idea how to solve it.

There shouldn't be any confusion. Each line is processed separately. For
every line, the first question you ask is: "is this line a comment?" You
do that by inspecting the first character of the line, line[0]. If it's
a '*' character, that line is a comment, so you ignore it and go round
the loop again. Only if it is *not* a comment do you continue to process
that line.

Then, when that line has been processed, you go round the loop again.
And again, the first thing you do is test to see if the line is a
comment line, by again inspecting line[0].

Try this program out, and see for yourself. It is *not* a solution to
your original requirement --- you made it clear that you intend to write
that yourself --- but it will *illustrate* my point here.

#include <stdio.h>

int main(void)
{
char line[130] = "";
while(fgets(line, sizeof line, stdin) != NULL)
{
if(line[0] != '*') /* that is, if this line is NOT a comment line */
{
fputs(line, stdout);
}
}
return 0;
}

Input:

* This is a comment, which will be ignored.
* So is this.
This line is not a comment, and must be printed.
This line isn't a comment either.
* But don't display this one.
This one is okay to display.
* Not this one.
This is the last line.

Processing:

Output:

This line is not a comment, and must be printed.
This line isn't a comment either.
This one is okay to display.
This is the last line.

And that's exactly what I suggested you should do, and that is, I think,
exactly what you need. I really don't see the problem.

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/16/2016 2:02:06 PM
```Mr Richard, sorry I am reading faster then I think. ;) Your solution is great. It was my mistake.
It was misunderstanding. You did exactly what is asked. Comments to avoid with if statement
(line[0] != '*') is what was looking for last 7 days. ;)

I didn't think that I can do it with strtok() function. But, this part is essential.

I will explain what is my problem now.

This is my new code (but not complete and will explain what is my problem now) for this part of my exercise:

---

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define FILENAME "netlist.txt"

typedef struct
{
char component[5];
unsigned a_node;
unsigned b_node;
char value[25];    // vidi kasnije da li ovo da prebacim u pointer ???
} Components;

typedef struct
{
char comp_new[5];
unsigned first_node;
unsigned second_node;
char val_new[25];

}SortComponents;

char line[130];

int main(void)
{
FILE *pFile = fopen(FILENAME, "r");
Components *series_connection = (Components*) malloc(siezeof(*series_connection));

if(pFile != NULL)
{
while(fgets(line, sizeof(line), pFile) != NULL)
{
if(line[0] != '*')
{

/*****************

Here comes my essential question.

******************/

}
}
}
else
{
printf("Wrong! Error.\n"); // I will change this error message later
break;
}

fclose(pFile);
free(series_connection);
series_connection = NULL;
return 0;
}

--

Now. My program must read this "netlist.txt" file with content like this. Look out, please, JUST READ this part.

* This is a comment
R1 0 1 (100/1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000)

--

OK, now we are here:
....

while(fgets(line, sizeof(line), pFile) != NULL)
{
if(line[0] != '*')
{

/*****************

Here comes my essential question.

******************/

}

.....

Now, my program must read text file and that text file put in the following form on the screen. I mean my program MUST print out on the screen next content

0 - R1(100/1) - 1
1 - C0(1/1000000) - 2
2 - L1(47/1000) - 3

---

What that means. During reading input text file, the program must make a sorting. Thats is reason why I have formulated a new struct.

typedef struct
{
char comp_new[5];
unsigned first_node;
unsigned second_node;
char val_new[25];

}SortComponents;

---

Why is this for ?

When program read a text file and automatically make a copy for each value of Component values into a new structure SortComponent. This new "structures" is for the calucaltions that will come later.

For instance.

When we read input text file and the program print out following conntent

---
0 - R1(100/1) - 1
1 - C0(1/1000000) - 2
2 - L1(47/1000) - 3

-> then comes (and I have solution for this part, partly):

ep> 0 1    (ep> is a cursor and after "ep>" comes white space, user put two unsigned integer
from 0 til 3, i.e 0 1 or 1 3, or 2 3, ... etc and according to that ask from user the program makes calcultation)

- > this part with calculations I have idea how to do it.

--

- > My question what is the smartest way to make this sort with strtok() function, I mean how to initialise a values from reading file (from Components) to a new structure SortComponent ?

```
 0
Dexterr
12/16/2016 2:30:34 PM
```On 16/12/16 14:30, Dexterr wrote:
> Mr Richard, sorry I am reading faster then I think. ;) Your solution is great. It was my mistake.
> It was misunderstanding. You did exactly what is asked. Comments to avoid with if statement
> (line[0] != '*') is what was looking for last 7 days. ;)
>
> I didn't think that I can do it with strtok() function. But, this part is essential.
>
> I will explain what is my problem now.
>
> This is my new code (but not complete and will explain what is my problem now) for this part of my exercise:
>
> ---
>
> #include <stdio.h>
> #include <stdlib.h>
> #include <string.h>
>
> #define FILENAME "netlist.txt"
>
> typedef struct
> {
>   char component[5];
>   unsigned a_node;
>   unsigned b_node;
>   char value[25];    // vidi kasnije da li ovo da prebacim u pointer ???
> } Components;
>
> typedef struct
> {
>   char comp_new[5];
>   unsigned first_node;
>   unsigned second_node;
>   char val_new[25];
>
> }SortComponents;
>
> char line[130];
>
> int main(void)
> {
>   FILE *pFile = fopen(FILENAME, "r");
>   Components *series_connection = (Components*) malloc(siezeof(*series_connection));

If you write it like this, *AS I SUGGESTED LAST TIME*:

Components *series_connection = malloc(sizeof *series_connection);

then not only is it a lot easier to type, but you're also more likely to
spot when you've misspelled sizeof as siezeof.

And you're still not checking whether the call succeeded.

Not that it matters, since you're not using it. (And indeed you don't
need it.)

Components series_connection = {0};

will give you a nice, normal struct to work with. But, as it turns out,
you don't need it.

> Now, my program must read text file and that text file
> put in the following form on the screen. I mean my
> program MUST print out on the screen next content
>
> 0 - R1(100/1) - 1
> 1 - C0(1/1000000) - 2
> 2 - L1(47/1000) - 3
>
> ---
>
> What that means. During reading input text file, the program must make a sorting.

All you have to do is move some fields around a little.

R1 0 1 (100/1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000)

has to become

0 - R1(100/1) - 1
1 - C0(1/1000000) - 2
2 - L1(47/1000) - 3

So you get your input line:

"R1 0 1 (100/1)"

Tokenise on spaces, keeping everything as a string:

"R1" "0" "1" "(100/1)"

Let's call these tokens t[0], t[1], t[2], t[3].

Now just output them like this:

printf("%s - %s%s - %s\n", t[1], t[0], t[3], t[2]);

and you're done.

> - > My question what is the smartest way to make
> this sort with strtok() function, I mean how to
> initialise a values from reading file (from
> Components) to a new structure SortComponent ?

The strtok function is for tokenising (which you *do* need to do), not
for sorting (which you don't). And you don't need either of your structs.

The following program should get you started:

#include <stdio.h>
#include <string.h>

#define FILENAME "netlist.txt"

#define NUM_FIELDS 4

int main(void)
{
char *component = NULL;
char *a_node = NULL;
char *b_node = NULL;
char *value = NULL;
char line[130] = "";
FILE *fp = fopen(FILENAME, "r");
if(fp != NULL)
{
while(fgets(line, sizeof line, fp) != NULL)
{
if(line[0] != '*')
{
component = strtok(line, " \t\n");
a_node = strtok(NULL, " \t\n");
b_node = strtok(NULL, " \t\n");
value = strtok(NULL, " \t\n");
if(component != NULL &&
a_node != NULL &&
b_node != NULL &&
value != NULL)
{
printf("%s - %s%s - %s\n",
b_node, a_node, value, component);
}
}
}
fclose(fp);
}
else
{
fprintf(stderr, "Can't find %s.\n", FILENAME);
}
return 0;
}

Input data:

\$ cat netlist.txt
* This is a comment
R1 0 1 (100/1)
C0 1 2 (1/1000000)
L1 2 3 (47/1000)

Process:

\$ ./components

Output:

1 - 0(100/1) - R1
2 - 1(1/1000000) - C0
3 - 2(47/1000) - L1

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/16/2016 3:20:14 PM
```Mr Richard, I have put it into a struct. What you think ? ;)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FILENAME "netlist.txt"

typedef struct
{
char *component;
char *a_node;
char *b_node;
char *value;
}Components;

char line[130] = "";

int main()
{

return 0;
}

{
FILE *fp = fopen(FILENAME, "r");
Components *series_connection = (Components*) malloc(sizeof *series_connection);
if(fp != NULL)
{
while(fgets(line, sizeof line, fp) != NULL)
{
if(line[0] != '*')
{
series_connection->component = strtok(line, " \t\n");
series_connection->a_node = strtok(NULL, " \t\n");
series_connection->b_node = strtok(NULL, " \t\n");
series_connection->value = strtok(NULL, " \t\n");
if(series_connection->component != NULL &&
series_connection->a_node != NULL &&
series_connection->b_node != NULL &&
series_connection->value != NULL)
{
printf("%s - %s%s - %s\n",
series_connection->b_node, series_connection->a_node,
series_connection->value, series_connection->component);
}
}
}
fclose(fp);
}
else
{
fprintf(stderr, "Can't find %s.\n", FILENAME);
}
}
```
 0
Dexterr
12/16/2016 4:54:10 PM
```On 16/12/16 16:54, Dexterr wrote:
> Mr Richard, I have put it into a struct. What you think ? ;)

I think you haven't been paying attention.

Putting it in a function is a good idea. Calling that function
readSortFunction is not such a good idea, since all functions are
and "Sort" doesn't describe what it does.

would be better.

> {
> 	FILE *fp = fopen(FILENAME, "r");
> 	Components *series_connection = (Components*) malloc(sizeof *series_connection);

Better than before, but lose the cast. It's completely unnecessary.

And, *yet again*, I suggest that you TEST the pointer before using it.
If you must use a pointer, that is. I don't see why you need to allocate
this space dynamically.

Apart from that, it looks fine to me.

To improve it, separate the three parts of the process into three parts:

2) process the line
3) print the line

Three different functions.

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/16/2016 5:00:03 PM
```> Putting it in a function is a good idea. Calling that function
> readSortFunction is not such a good idea, since all functions are
> and "Sort" doesn't describe what it does.
>

-> I am not sure that I understand. Is the problem my name of the function as I named it,
or ... ?

> Better than before, but lose the cast. It's completely unnecessary.
>
> And, *yet again*, I suggest that you TEST the pointer before using it.

-> You mean on *series_conection, or ?

> If you must use a pointer, that is. I don't see why you need to allocate
> this space dynamically.

- > I don't need but I think that professor will like to see it, because in his
examples, he allocate memory when he has struct defined variables
and read the files withe FILE *fp = fopen ...

>
> Apart from that, it looks fine to me.
>
> To improve it, separate the three parts of the process into three parts:
>
> 2) process the line
> 3) print the line
>
> Three different functions.

Good idea. I will do it. ;)

```
 0
Dexterr
12/16/2016 5:32:25 PM
```On 16/12/16 17:32, Dexterr wrote:
>
>> Putting it in a function is a good idea. Calling that function
>> readSortFunction is not such a good idea, since all functions are
>> and "Sort" doesn't describe what it does.
>>
>
> -> I am not sure that I understand. Is the problem my name of the function as I named it,
>      or ... ?

Your name obeys the rules of C. It just disobeys the rules of picking a
good name. If you don't mind about that, then okay.

>> Better than before, but lose the cast. It's completely unnecessary.
>>
>> And, *yet again*, I suggest that you TEST the pointer before using it.
>
> -> You mean on *series_conection, or ?

Yes, and on *any* value you get from malloc.

series_connection = malloc(sizeof *series_connection);
if(series_connection != NULL)
{
everything's fine and you can carry on.
}
else
{
your memory request was refused - if you have no better plan,
terminate the program.
}

>> If you must use a pointer, that is. I don't see why you need to allocate
>> this space dynamically.
>
> - > I don't need but I think that professor will like to see it, because in his
>       examples, he allocate memory when he has struct defined variables
>      and read the files withe FILE *fp = fopen ...

Bring him on, and we'll show him how to do it properly.

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/16/2016 5:38:49 PM
```Mr Richard you have a right, I should have a better names for functions! I will try to follow that rule.

I have now better version. Also before I have forget to free a memory for the pointer which is big mistake! I have corrected that.

---

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FILENAME "kurton.txt"

typedef struct
{
char *component;  // rijesiti component mora biti max. "5 Zeichen"
char *a_node;
char *b_node;
char *value;
} Components;

char line[130] = "";

int main()
{

return 0;
}

// Function for reading and print out the conent of the file after sorting
{
// Opening a text file test.netlist
FILE *fp = fopen(FILENAME, "r");
// Memory allocation for struct Components
Components *series_connection = (Components*) malloc(sizeof *series_connection);
// Check the pointer series_connection
if(series_connection == NULL)
{
fputs("[ERR] Out of memory", stderr);
exit(2);
}
if(fp != NULL)
{
// Read the file fp line by line
while(fgets(line, sizeof line, fp) != NULL)
{
// If the line begin with * sign, that is a comment and must be skiped,
// the whole comment line
if(line[0] != '*')
{
// Adding the values from netlist file into a variables defined in
// struct Components
series_connection->component = strtok(line, " \t\n");
series_connection->a_node = strtok(NULL, " \t\n");
series_connection->b_node = strtok(NULL, " \t\n");
series_connection->value = strtok(NULL, " \t\n");
if(series_connection->component != NULL &&
series_connection->a_node != NULL &&
series_connection->b_node != NULL &&
series_connection->value != NULL)
{
printf("%s - %s%s - %s\n",
series_connection->b_node, series_connection->a_node,
series_connection->value, series_connection->component);
}
}
}
// Close the file fp after reading and sorting
fclose(fp);
}
else
{
fprintf(stderr, "Can't find %s.\n", FILENAME);
}
// Memory free for the pointer varible series_connection of type Components
free(series_connection);
series_connection = NULL;
}

---

- now I have to do 3 functions, but problem is how to split from this function 3 more functions, because all three parts are in the while loop.

- > one more think, for instance the variable components must have limit for 5 characters.
I have put it as a pointer in struct. If I turn it in array - char component[5], I have problem
in function to add a values from file.

I mean how to reffer pointer to pointer from struct ?

For instance how to do it here ?

series_connection->component = strtok(line, " \t\n");
```
 0
Dexterr
12/16/2016 6:03:59 PM
```On 16/12/16 18:03, Dexterr wrote:
> 	// Memory allocation for struct Components
> 	Components *series_connection = (Components*) malloc(sizeof *series_connection);

For the last time: you don't need the cast.

Components *series_connection = malloc(sizeof *series_connection);

(If you can't learn, I can't teach you.)

> - now I have to do 3 functions, but problem is how to split from
> this function 3 more functions, because all three parts are in
> the while loop.

int linenumber = 0;

while(fgets(line, sizeof line, fp) != NULL)
{
++linenumber;

if(is_comment(line) == 0)
{
if(tokenise(series_connection, line)) == NUM_FIELDS)
{
output(series_connection);
}
else
{
fprintf(stderr,
"Input error on line %d.\n",
linenumber);
}
}
}

That just leaves you to write is_comment(), tokenise() and output().

Here's a freebie: is_comment():

int is_comment(const char *line)
{
return line[0] == '*';
}

> - > one more think, for instance the variable components must have limit for 5 characters.
> I have put it as a pointer in struct. If I turn it in array - char component[5], I have problem
> in function to add a values from file.
>
> I mean how to reffer pointer to pointer from struct ?
>
> For instance how to do it here ?
>
> series_connection->component = strtok(line, " \t\n");

if(strlen(series_connection->component) > MAX_COMPONENT_LENGTH)
{
reject the line
}

If you would rather that series_connection contained arrays rather than
pointers, that's fine. You can set up a pointer like this:

char *token = strtok(line, " \t\n");
if(token != NULL)
{
if(strlen(token) >= sizeof series_connection->component)
{
report an error and reject the line
}
else
{
strcpy(series_connection->component, token);
}
}

This gives you even more reason to put all this sort of thing in a
separate function.

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/16/2016 6:40:27 PM
```Richard Heathfield <rjh@cpax.org.uk> writes:

> On 16/12/16 18:03, Dexterr wrote:
>> 	// Memory allocation for struct Components
>> 	Components *series_connection = (Components*) malloc(sizeof
>> *series_connection);
>
> For the last time: you don't need the cast.
>
> Components *series_connection = malloc(sizeof *series_connection);
>
> (If you can't learn, I can't teach you.)

It's possible the OP has been told to use a cast, or, at least it's been
there in examples in class or in the course materials.  Would you rather
do it the way the person marking your paper does it, or the way someone
on Usenet told you to do it? :-)

<snip>
--
Ben.
```
 0
Ben
12/16/2016 8:16:12 PM
```Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> Richard Heathfield <rjh@cpax.org.uk> writes:
>> On 16/12/16 18:03, Dexterr wrote:
>>> 	// Memory allocation for struct Components
>>> 	Components *series_connection = (Components*) malloc(sizeof
>>> *series_connection);
>>
>> For the last time: you don't need the cast.
>>
>> Components *series_connection = malloc(sizeof *series_connection);
>>
>> (If you can't learn, I can't teach you.)
>
> It's possible the OP has been told to use a cast, or, at least it's been
> there in examples in class or in the course materials.  Would you rather
> do it the way the person marking your paper does it, or the way someone
> on Usenet told you to do it? :-)
>
> <snip>

It could also be helpful to explain *why* the cast shouldn't be there.
This has been explained many times, but perhaps not in this thread.

malloc() returns a pointer result of type void*, which is more or less a
generic pointer type.  C permits a value of type void* to be implicitly
converted (via assignment, initialization, etc.) to any
pointer-to-object type, without the need for a cast.

That's why you don't *need* the cast, but it doesn't explain why you
*shouldn't* use the cast.

A cast can in effect override type checking.  The syntax to convert from
one numeric type to another (which is usually a safe operation) is the
same as the syntax to convert from one pointer type to another, or from
an integer to a pointer or vice versa (such conversions can be very
dangerous).  After decades of experience, most C programmers have
concluded that minimizing casts, and depending as much as possible on
implicit conversions, is the safest approach.  It means that any time
there is a cast, it should be viewed with some suspicion.

If you write:

some_type *pointer = (some_type*)malloc(sizeof *pointer);

then you're specifying the same conversion that would have been done
implicitly without the cast.  But you're also writing the type name
twice.  The reader has to verify that the type in the cast matches the
type of the pointer, and that the conversion is appropriate.

In earlier versions of C (C90 and earlier), it was legal to call a
function with no visible declaration; such a function was *assumed* to
return an int result.  So if you forgot the "#include <stdlib.h>" that
provides the declaration of malloc() *and* omitted the cast, the
compiler would probably warn you about an implicit int-to-pointer
conversion.  If you forgot the #include and added the cast, the cast
would specify a conversion from int to some_type* rather than from void*
to some_type* -- and the compiler would not complain about it; by using
a cast, you promise the compiler that you know what the heck you're
doing.  That consideration *mostly* doesn't apply anymore, but some
compilers still default to C90 rules.

This is, not surprisingly, a frequently asked question, covered in
http://www.c-faq.com/ questions 7.6 and following.

--
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
```
 0
Keith
12/16/2016 8:46:20 PM
```> For the last time: you don't need the cast.
>
> Components *series_connection = malloc(sizeof *series_connection);
>
> (If you can't learn, I can't teach you.)

-> OK, sorry, I have change it. ;) Thanks for the note.

Now I have a problem how to write tokenise function:

int tokenise(Components *ser_con, --> here comes line)
{
ser_con->component = strtok(line, " \t\n");
ser_con->a_node = strtok(NULL, " \t\n");
ser_con->b_node = strtok(NULL, " \t\n");
ser_con->value = strtok(NULL, " \t\n");

return <something>
}

- this part confuse me - f(tokenise(series_connection, line)) == NUM_FIELDS)

OK, NUM_FILDS is defined as 2

I am pretty bad with functions and arguments, thats make confusion.

This function must return integer of 4 I suppose.

One more question:

By function

is comment(const char *line)
{
return line[0] == '*';
}

- > this solution is great, but I am not sure that I understand it completely
for instance when line[0] is not equal to '*' in that case the function return some
value od line[0] which is non-zero that means TRUE

and when we go back

if(is_comment(line) == 0) - > that confuse me.
```
 0
Dexterr
12/17/2016 1:43:13 PM
```On Friday, December 16, 2016 at 9:46:22 PM UTC+1, Keith Thompson wrote:
> Ben Bacarisse <ben.usenet@bsb.me.uk> writes:
> > Richard Heathfield <rjh@cpax.org.uk> writes:
> >> On 16/12/16 18:03, Dexterr wrote:
> >>> 	// Memory allocation for struct Components
> >>> 	Components *series_connection = (Components*) malloc(sizeof
> >>> *series_connection);
> >>
> >> For the last time: you don't need the cast.
> >>
> >> Components *series_connection = malloc(sizeof *series_connection);
> >>
> >> (If you can't learn, I can't teach you.)
> >
> > It's possible the OP has been told to use a cast, or, at least it's been
> > there in examples in class or in the course materials.  Would you rather
> > do it the way the person marking your paper does it, or the way someone
> > on Usenet told you to do it? :-)
> >
> > <snip>
>
> It could also be helpful to explain *why* the cast shouldn't be there.
> This has been explained many times, but perhaps not in this thread.
> Feel free to stop reading if you already know this stuff.
>
> malloc() returns a pointer result of type void*, which is more or less a
> generic pointer type.  C permits a value of type void* to be implicitly
> converted (via assignment, initialization, etc.) to any
> pointer-to-object type, without the need for a cast.
>
> That's why you don't *need* the cast, but it doesn't explain why you
> *shouldn't* use the cast.
>
> A cast can in effect override type checking.  The syntax to convert from
> one numeric type to another (which is usually a safe operation) is the
> same as the syntax to convert from one pointer type to another, or from
> an integer to a pointer or vice versa (such conversions can be very
> dangerous).  After decades of experience, most C programmers have
> concluded that minimizing casts, and depending as much as possible on
> implicit conversions, is the safest approach.  It means that any time
> there is a cast, it should be viewed with some suspicion.
>
> If you write:
>
>     some_type *pointer = (some_type*)malloc(sizeof *pointer);
>
> then you're specifying the same conversion that would have been done
> implicitly without the cast.  But you're also writing the type name
> twice.  The reader has to verify that the type in the cast matches the
> type of the pointer, and that the conversion is appropriate.
>
> In earlier versions of C (C90 and earlier), it was legal to call a
> function with no visible declaration; such a function was *assumed* to
> return an int result.  So if you forgot the "#include <stdlib.h>" that
> provides the declaration of malloc() *and* omitted the cast, the
> compiler would probably warn you about an implicit int-to-pointer
> conversion.  If you forgot the #include and added the cast, the cast
> would specify a conversion from int to some_type* rather than from void*
> to some_type* -- and the compiler would not complain about it; by using
> a cast, you promise the compiler that you know what the heck you're
> doing.  That consideration *mostly* doesn't apply anymore, but some
> compilers still default to C90 rules.
>
> This is, not surprisingly, a frequently asked question, covered in
> http://www.c-faq.com/ questions 7.6 and following.
>
> --
> Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
> Working, but not speaking, for JetHead Development, Inc.
> "We must do something.  This is something.  Therefore, we must do this."
>     -- Antony Jay and Jonathan Lynn, "Yes Minister"

Thanks Mr Keith for your response.
```
 0
Dexterr
12/17/2016 1:47:42 PM
```On Friday, December 16, 2016 at 9:16:19 PM UTC+1, Ben Bacarisse wrote:
> Richard Heathfield <rjh@cpax.org.uk> writes:
>
> > On 16/12/16 18:03, Dexterr wrote:
> >> 	// Memory allocation for struct Components
> >> 	Components *series_connection = (Components*) malloc(sizeof
> >> *series_connection);
> >
> > For the last time: you don't need the cast.
> >
> > Components *series_connection = malloc(sizeof *series_connection);
> >
> > (If you can't learn, I can't teach you.)
>
> It's possible the OP has been told to use a cast, or, at least it's been
> there in examples in class or in the course materials.  Would you rather
> do it the way the person marking your paper does it, or the way someone
> on Usenet told you to do it? :-)
>
> <snip>
> --
> Ben.

Thanks Mr Ben on your response. My professor make cast but in his code examples have a mistakes. I prefer suggestions from people like you from UseNet. ;) If you ask me personaly.
```
 0
Dexterr
12/17/2016 1:49:27 PM
```On Sat, 17 Dec 2016 05:43:13 -0800 (PST), Dexterr <dejangru@gmail.com>
wrote:
<snip>

>One more question:
>
>By function
>
>is comment(const char *line)
>{
>  return line[0] == '*';
>}
>
>- > this solution is great, but I am not sure that I understand it completely
>for instance when line[0] is not equal to '*' in that case the function return some
>value od line[0] which is non-zero that means TRUE

The == operator always evaluates to 0 or 1, depending on the equality
of the two operands.  Therefore, the expression of the return
statement will always have a value of 0 or 1.  If the first character
is not '*', the expression will evaluate to 0 and that is the return
value.  The function never returns to value of line[0].  It only uses
that value as one of the operands to ==

>and when we go back
>
>if(is_comment(line) == 0) - > that confuse me.

As noted above, the function returns 0 when line[0] is not '*'.  For
most boolean style functions, 0 is regarded as false.  That is, the
line is not a comment.  When line[0] is '*', the function returns 1,
which is regarded as true.  That is, the line is a comment.

--
Remove del for email
```
 0
Barry
12/17/2016 4:48:00 PM
```On Saturday, December 17, 2016 at 5:48:09 PM UTC+1, Barry Schwarz wrote:
> On Sat, 17 Dec 2016 05:43:13 -0800 (PST), Dexterr <dejangru@gmail.com>
> wrote:
> <snip>
>
> >One more question:
> >
> >By function
> >
> >is comment(const char *line)
> >{
> >  return line[0] == '*';
> >}
> >
> >- > this solution is great, but I am not sure that I understand it completely
> >for instance when line[0] is not equal to '*' in that case the function return some
> >value od line[0] which is non-zero that means TRUE
>
> The == operator always evaluates to 0 or 1, depending on the equality
> of the two operands.  Therefore, the expression of the return
> statement will always have a value of 0 or 1.  If the first character
> is not '*', the expression will evaluate to 0 and that is the return
> value.  The function never returns to value of line[0].  It only uses
> that value as one of the operands to ==
>
> >and when we go back
> >
> >if(is_comment(line) == 0) - > that confuse me.
>
> As noted above, the function returns 0 when line[0] is not '*'.  For
> most boolean style functions, 0 is regarded as false.  That is, the
> line is not a comment.  When line[0] is '*', the function returns 1,
> which is regarded as true.  That is, the line is a comment.
>
> --
> Remove del for email

Thanks Mr Barry on your response.

This is now my code with very generios help of Mr Richard Heathfield.

Here I have only problem with the function - "tokenise()", I have no idea for a second argument and return.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FILENAME "netlist.txt"
#define NUM_FIELDS 4

typedef struct
{
char *component;
char *a_node;
char *b_node;
char *value;
}Components;

int is_comment(const char *line);
int tokenise();
void output(Components *ser_conn);

char line[130] = "";
int line_number = 0;
Components *series_connection;

int main(void)
{

return 0;
}

{
FILE *fp = fopen(FILENAME, "r");

series_connection = malloc(sizeof *series_connection);

if(series_connection == NULL)
{
fputs("[ERR] Out of memory", stderr);
exit(2);
}

if(fp != NULL)
{
while(fgets(line, sizeof line, fp) != NULL)
{
++line_number;

if(is_comment(line) == 0)
{
/***********  my problem

if(tokenise(series_connection, line) == NUM_FIELDS)

************/
{
output(series_connection);
} // End of tokenise function - if condition
else
{
fprintf(stderr, "Input error on line %d \n", line_number);
}
}
}
// Close the file fp after reading and sorting
fclose(fp);
}
else
{
fprintf(stderr, "Can't find %s.\n", FILENAME);
}
free(series_connection);
series_connection = NULL;
} // End of readComponentFile function

int is_comment(const char *line)
{
return line[0] == '*';
}

/********************* - my problem -  here is the 2nd argument and return value

int tokenise(Components *ser_con, const char *line)
{
ser_con->component = strtok(line, " \t\n");
ser_con->a_node = strtok(NULL, " \t\n");
ser_con->b_node = strtok(NULL, " \t\n");
ser_con->value = strtok(NULL, " \t\n");
}

**********************/
void output(Components *ser_conn)
{
if(ser_conn->component != NULL &&
ser_conn->a_node != NULL &&
ser_conn->b_node != NULL &&
ser_conn->value != NULL)
{
printf("%s - %s%s - %s\n",
ser_conn->b_node, ser_conn->a_node, ser_conn->value,
ser_conn->component);
}

}
```
 0
Dexterr
12/17/2016 8:03:40 PM
```Dexterr <dejangru@gmail.com> writes:
[...]
> int is_comment(const char *line);
[...]
>       if(is_comment(line) == 0)

The value returned by the is_comment function is logically Boolean.
Starting with C99, you could use the built-in type _Bool (or bool if you
have #include <stdbool.h>), but it's still reasonable to use int, with
zero for false and any non-zero value for true.  The comparison
operators ("==", "<", et al) still yield a result of type int with the
value 0 or 1.

Boolean values should rarely be compared for equality.

Rather than

if(is_comment(line) == 0)

it would be much clearer to write:

if (! is_comment(line))

--
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something.  This is something.  Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
```
 0
Keith
12/17/2016 8:22:27 PM
```On Saturday, December 17, 2016 at 9:21:30 PM UTC+1, Keith Thompson wrote:
> Dexterr <dejangru@gmail.com> writes:
> [...]
> > int is_comment(const char *line);
> [...]
> >       if(is_comment(line) == 0)
>
> The value returned by the is_comment function is logically Boolean.
> Starting with C99, you could use the built-in type _Bool (or bool if you
> have #include <stdbool.h>), but it's still reasonable to use int, with
> zero for false and any non-zero value for true.  The comparison
> operators ("==", "<", et al) still yield a result of type int with the
> value 0 or 1.
>
> Boolean values should rarely be compared for equality.
>
> Rather than
>
>     if(is_comment(line) == 0)
>
> it would be much clearer to write:
>
>     if (! is_comment(line))
>
> --
> Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
> Working, but not speaking, for JetHead Development, Inc.
> "We must do something.  This is something.  Therefore, we must do this."
>     -- Antony Jay and Jonathan Lynn, "Yes Minister"

Yes. I prefer this option - if(! is_comment(line))

Thanks Mr Keith for suggestion. ;)
```
 0
Dexterr
12/17/2016 8:23:44 PM
```Now I have very nice code. But I can't get an idea how to finish "tokenise()" function.
The idea from Mr Richard is great but I can't catch what to put as a return value.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FILENAME "netlist.txt"
#define NUM_FIELDS 4

typedef struct
{
char *component;
char *a_node;
char *b_node;
char *value;
}Components;

int is_comment(const char *line);
//int tokenise();
void output(Components *ser_conn);

char line[130] = "";
int line_number = 0;
Components *series_connection;

int main(void)
{

return 0;
}

{
FILE *fp = fopen(FILENAME, "r");

series_connection = malloc(sizeof *series_connection);

if(series_connection == NULL)
{
fputs("[ERR] Out of memory", stderr);
exit(2);
}

if(fp != NULL)
{
while(fgets(line, sizeof line, fp) != NULL)
{
++line_number;

if(!is_comment(line))
{
// if(tokenise(series_connection, line) == NUM_FIELDS)
// {
series_connection->component = strtok(line, " \t\n");
series_connection->a_node = strtok(NULL, " \t\n");
series_connection->b_node = strtok(NULL, " \t\n");
series_connection->value = strtok(NULL, " \t\n");
output(series_connection);
// }
} // End of tokenise function - if condition
else
{
fprintf(stderr, "Input error on line %d \n", line_number);
}
}
// Close the file fp after reading and sorting
fclose(fp);
}
else
{
fprintf(stderr, "Can't find %s.\n", FILENAME);
}
free(series_connection);
series_connection = NULL;
} // End of readComponentFile function

int is_comment(const char *line)
{
return line[0] == '*';
}

/*
int tokenise(Components *ser_con, const char *line)
{
ser_con->component = strtok(line, " \t\n");
ser_con->a_node = strtok(NULL, " \t\n");
ser_con->b_node = strtok(NULL, " \t\n");
ser_con->value = strtok(NULL, " \t\n");

return
}
*/

void output(Components *ser_conn)
{
if(ser_conn->component != NULL &&
ser_conn->a_node != NULL &&
ser_conn->b_node != NULL &&
ser_conn->value != NULL)
{
printf("%s - %s%s - %s\n",
ser_conn->b_node, ser_conn->a_node, ser_conn->value,
ser_conn->component);
}

}
```
 0
Dexterr
12/17/2016 8:26:19 PM
```What about:?
int tokenise(Components *ser_con, const char *line)
{
ser_con->component = strtok(line, " \t\n");
ser_con->a_node = strtok(NULL, " \t\n");
ser_con->b_node = strtok(NULL, " \t\n");
ser_con->value = strtok(NULL, " \t\n");

return ser_con->value!=0 ;
}
So if all element have their string
Return 1 [struct fill] else Return 0...
```
 0
asetofsymbols
12/18/2016 8:41:28 PM
```On Sunday, December 18, 2016 at 9:41:36 PM UTC+1, asetof...@gmail.com wrote:
> int tokenise(Components *ser_con, const char *line)
> {
>   ser_con->component = strtok(line, " \t\n");
>   ser_con->a_node = strtok(NULL, " \t\n");
>   ser_con->b_node = strtok(NULL, " \t\n");
>   ser_con->value = strtok(NULL, " \t\n");
>
>
>   return ser_con->value!=0 ;
> }
> So if all element have their string
> Return 1 [struct fill] else Return 0...

NOT Work!
```
 0
Dexterr
12/18/2016 9:04:57 PM
```On Sunday, December 18, 2016 at 9:41:36 PM UTC+1, asetof...@gmail.com wrote:
> int tokenise(Components *ser_con, const char *line)
> {
>   ser_con->component = strtok(line, " \t\n");
>   ser_con->a_node = strtok(NULL, " \t\n");
>   ser_con->b_node = strtok(NULL, " \t\n");
>   ser_con->value = strtok(NULL, " \t\n");
>
>
>   return ser_con->value!=0 ;
> }
> So if all element have their string
> Return 1 [struct fill] else Return 0...

This do not work!

While we have -

if(tokenise(series_connection, line) == NUM_FIELDS)

NUM_FIELDS = 4

```
 0
Dexterr
12/18/2016 9:08:17 PM
```
int tokenise(Components *ser_con, const char *line)
{
ser_con->component = strtok(line, " \t\n");
ser_con->a_node = strtok(NULL, " \t\n");
ser_con->b_node = strtok(NULL, " \t\n");
ser_con->value = strtok(NULL, " \t\n");

return ser_con->value!=0 ;
}
So if all element have their string
Return 1 [struct fill] else Return 0...
So if all 4 inputs are taken it would
be
if(tokenise(series_connection, line) == 1) allok;
Or
if(tokenise(series_connection, line))
allok;
```
 0
asetofsymbols
12/19/2016 2:14:45 PM
```On Monday, December 19, 2016 at 3:14:55 PM UTC+1, asetof...@gmail.com wrote:
> int tokenise(Components *ser_con, const char *line)
> {
>   ser_con->component = strtok(line, " \t\n");
>   ser_con->a_node = strtok(NULL, " \t\n");
>   ser_con->b_node = strtok(NULL, " \t\n");
>   ser_con->value = strtok(NULL, " \t\n");
>
>
>
>   return ser_con->value!=0 ;
> }
> So if all element have their string
> Return 1 [struct fill] else Return 0...
> So if all 4 inputs are taken it would
> be
> if(tokenise(series_connection, line) == 1) allok;
> Or
> if(tokenise(series_connection, line))
>       allok;

----

- NO, it does not work! Sorry.

This is my code:

----

//-----------------------------------------------------------------------------
// input_struc_ver_03.c
//
// modifikovano rijesenje Richarda H. sa structures i functions
// nova verzija sa nove tri funkcije
//
// Authors: DI Dr. Dejan Grubesic
//-----------------------------------------------------------------------------
//

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FILENAME "netlist.txt"
#define NUM_FIELDS 4

typedef struct
{
char *component;
char *a_node;
char *b_node;
char *value;
}Components;

int is_comment(const char *line);
//int tokenise();
void output(Components *ser_conn);

char line[130] = "";
int line_number = 0;
Components *series_connection;

int main(void)
{
return 0;
}

{
FILE *fp = fopen(FILENAME, "r");

series_connection = malloc(sizeof *series_connection);

if(series_connection == NULL)
{
fputs("[ERR] Out of memory", stderr);
exit(2);
}

if(fp != NULL)
{
while(fgets(line, sizeof line, fp) != NULL)
{
++line_number;

if(!is_comment(line))
{
if(tokenise(series_connection, line) == NUM_FIELDS)
{

// series_connection->component = strtok(line, " \t\n");
// series_connection->a_node = strtok(NULL, " \t\n");
// series_connection->b_node = strtok(NULL, " \t\n");
// series_connection->value = strtok(NULL, " \t\n");

output(series_connection);

}
} // End of tokenise function - if condition
else
{
fprintf(stderr, "Input error on line %d \n", line_number);
}
}
// Close the file fp after reading and sorting
fclose(fp);
}
else
{
fprintf(stderr, "Can't find %s.\n", FILENAME);
}
free(series_connection);
series_connection = NULL;
} // End of readComponentFile function

int is_comment(const char *line)
{
return line[0] == '*';
}

int tokenise(Components *ser_con, const char *line)
{
ser_con->component = strtok(line, " \t\n");
ser_con->a_node = strtok(NULL, " \t\n");
ser_con->b_node = strtok(NULL, " \t\n");
ser_con->value = strtok(NULL, " \t\n");

return ser_con->value != 0;
}

void output(Components *ser_conn)
{
if(ser_conn->component != NULL &&
ser_conn->a_node != NULL &&
ser_conn->b_node != NULL &&
ser_conn->value != NULL)
{
printf("%s - %s%s - %s\n",
ser_conn->b_node, ser_conn->a_node, ser_conn->value,
ser_conn->component);
}

}

----

This is what the compiler said.

MacBook-Pro-od-Dejan:NED putolov\$ ./ver_03
Can't find netlist.txt.
MacBook-Pro-od-Dejan:NED putolov\$ gcc -Wall -o ver_03 input_struct_ver_03.c
input_struct_ver_03.c:61:11: warning: implicit declaration of function
'tokenise' is invalid in C99 [-Wimplicit-function-declaration]
if(tokenise(series_connection, line) == NUM_FIELDS)
^
input_struct_ver_03.c:97:31: warning: passing 'const char *' to parameter of
ser_con->component = strtok(line, " \t\n");
^~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/string.h:90:20: note:
passing argument to parameter '__str' here
char    *strtok(char *__str, const char *__sep);
^
2 warnings generated.
MacBook-Pro-od-Dejan:NED putolov\$ ./ver_03
MacBook-Pro-od-Dejan:NED putolov\$
```
 0
Dexterr
12/19/2016 6:38:39 PM
```On Monday, December 19, 2016 at 3:14:55 PM UTC+1, asetof...@gmail.com wrote:
> int tokenise(Components *ser_con, const char *line)
> {
>   ser_con->component = strtok(line, " \t\n");
>   ser_con->a_node = strtok(NULL, " \t\n");
>   ser_con->b_node = strtok(NULL, " \t\n");
>   ser_con->value = strtok(NULL, " \t\n");
>
>
>
>   return ser_con->value!=0 ;
> }
> So if all element have their string
> Return 1 [struct fill] else Return 0...
> So if all 4 inputs are taken it would
> be
> if(tokenise(series_connection, line) == 1) allok;
> Or
> if(tokenise(series_connection, line))
>       allok;

----

- Thanks on your response, but unfortunately it does not work at all.

This is my code:

----

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define FILENAME "netlist.txt"
#define NUM_FIELDS 4

typedef struct
{
char *component;
char *a_node;
char *b_node;
char *value;
}Components;

int is_comment(const char *line);
//int tokenise();
void output(Components *ser_conn);

char line[130] = "";
int line_number = 0;
Components *series_connection;

int main(void)
{
return 0;
}

{
FILE *fp = fopen(FILENAME, "r");

series_connection = malloc(sizeof *series_connection);

if(series_connection == NULL)
{
fputs("[ERR] Out of memory", stderr);
exit(2);
}

if(fp != NULL)
{
while(fgets(line, sizeof line, fp) != NULL)
{
++line_number;

if(!is_comment(line))
{
if(tokenise(series_connection, line) == NUM_FIELDS)
{

// series_connection->component = strtok(line, " \t\n");
// series_connection->a_node = strtok(NULL, " \t\n");
// series_connection->b_node = strtok(NULL, " \t\n");
// series_connection->value = strtok(NULL, " \t\n");

output(series_connection);

}
} // End of tokenise function - if condition
else
{
fprintf(stderr, "Input error on line %d \n", line_number);
}
}
// Close the file fp after reading and sorting
fclose(fp);
}
else
{
fprintf(stderr, "Can't find %s.\n", FILENAME);
}
free(series_connection);
series_connection = NULL;
} // End of readComponentFile function

int is_comment(const char *line)
{
return line[0] == '*';
}

int tokenise(Components *ser_con, const char *line)
{
ser_con->component = strtok(line, " \t\n");
ser_con->a_node = strtok(NULL, " \t\n");
ser_con->b_node = strtok(NULL, " \t\n");
ser_con->value = strtok(NULL, " \t\n");

return ser_con->value != 0;
}

void output(Components *ser_conn)
{
if(ser_conn->component != NULL &&
ser_conn->a_node != NULL &&
ser_conn->b_node != NULL &&
ser_conn->value != NULL)
{
printf("%s - %s%s - %s\n",
ser_conn->b_node, ser_conn->a_node, ser_conn->value,
ser_conn->component);
}

}

----

- ... and this is what my compiler said:

----

MacBook-Pro-od-Dejan:NED putolov\$ ./ver_03
Can't find netlist.txt.
MacBook-Pro-od-Dejan:NED putolov\$ gcc -Wall -o ver_03 input_struct_ver_03.c
input_struct_ver_03.c:61:11: warning: implicit declaration of function
'tokenise' is invalid in C99 [-Wimplicit-function-declaration]
if(tokenise(series_connection, line) == NUM_FIELDS)
^
input_struct_ver_03.c:97:31: warning: passing 'const char *' to parameter of
ser_con->component = strtok(line, " \t\n");
^~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/include/string.h:90:20: note:
passing argument to parameter '__str' here
char    *strtok(char *__str, const char *__sep);
^
2 warnings generated.
MacBook-Pro-od-Dejan:NED putolov\$ ./ver_03
MacBook-Pro-od-Dejan:NED putolov\$

----

- > when I start a program with - > ./ver_03

I have got nothing!
```
 0
Dexterr
12/19/2016 6:43:00 PM
```On 19/12/16 18:38, Dexterr wrote:
> On Monday, December 19, 2016 at 3:14:55 PM UTC+1, asetof...@gmail.com wrote:
<snip>
>> if(tokenise(series_connection, line))
>>       allok;
>
> ----
>
> - NO, it does not work! Sorry.

Yes, you have to be careful whose advice you follow.

> This is my code:

....which is beginning to look quite clean and well-structured (although
it isn't quite there yet).

> //-----------------------------------------------------------------------------
> // input_struc_ver_03.c
> //
> // modifikovano rijesenje Richarda H. sa structures i functions
> // nova verzija sa nove tri funkcije
> //
> // Authors: DI Dr. Dejan Grubesic
> //-----------------------------------------------------------------------------
> //
>
> #include <stdio.h>
> #include <string.h>
> #include <stdlib.h>
>
> #define FILENAME "netlist.txt"
> #define NUM_FIELDS 4

Good.

>
> typedef struct
> {
>   char *component;
>   char *a_node;
>   char *b_node;
>   char *value;
> }Components;
>
> int is_comment(const char *line);
> //int tokenise();

Remove the //, and add void. This will get rid of one of your compiler
diagnostic messages.

int tokenise(void);

> void output(Components *ser_conn);
>
> char line[130] = "";
> int line_number = 0;
> Components *series_connection;

Why have you put these at file scope?

>
> int main(void)
> {
>   return 0;
> }
>
> {
>   FILE *fp = fopen(FILENAME, "r");
>
>   series_connection = malloc(sizeof *series_connection);
>
>   if(series_connection == NULL)
>   {
>   	fputs("[ERR] Out of memory", stderr);
>   	exit(2);
>   }
>
>   if(fp != NULL)
>   {
>   	while(fgets(line, sizeof line, fp) != NULL)
>   	{
>   	  ++line_number;
>
>       if(!is_comment(line))
>       {
>        if(tokenise(series_connection, line) == NUM_FIELDS)

Okay, so we are expecting tokenise() to return the number of fields
successfully parsed.

>        {
>
>         // series_connection->component = strtok(line, " \t\n");
>         // series_connection->a_node = strtok(NULL, " \t\n");
>         // series_connection->b_node = strtok(NULL, " \t\n");
>         // series_connection->value = strtok(NULL, " \t\n");

That can all go.

>
>         output(series_connection);
>
>        }
>       } // End of tokenise function - if condition
>       else
>       {
>          fprintf(stderr, "Input error on line %d \n", line_number);
>       }
>     }
>     // Close the file fp after reading and sorting
>     fclose(fp);
>   }
>   else
>   {
>     fprintf(stderr, "Can't find %s.\n", FILENAME);
>   }
>   free(series_connection);
>   series_connection = NULL;
> } // End of readComponentFile function
>
> int is_comment(const char *line)
> {
>   return line[0] == '*';
> }
>
>
> int tokenise(Components *ser_con, const char *line)

You can't make line const if you want to split the line into tokens.
Removing const will get rid of your other compiler diagnostic message.

> {
>   ser_con->component = strtok(line, " \t\n");
>   ser_con->a_node = strtok(NULL, " \t\n");
>   ser_con->b_node = strtok(NULL, " \t\n");
>   ser_con->value = strtok(NULL, " \t\n");
>
>   return ser_con->value != 0;

Nope. Since your caller is expecting the number of fields successfully
parsed, you want something like this:

int tokenise(Components *ser_con, char *line)
{
int successes = 0;

if((ser_con->component = strtok(line, " \t\n")) != NULL) ++successes;
if((ser_con->a_node = strtok(NULL, " \t\n")) != NULL) ++successes;
if((ser_con->b_node = strtok(NULL, " \t\n")) != NULL) ++successes;
if((ser_con->value = strtok(NULL, " \t\n")) != NULL) ++successes;

return successes;
> }
>
>
> void output(Components *ser_conn)
> {
>   if(ser_conn->component != NULL &&
>      ser_conn->a_node != NULL &&
>      ser_conn->b_node != NULL &&
>      ser_conn->value != NULL)

You already tested this in the caller. You can do it there, or you can
do it here, but there's no need to do it in /both/ places.

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/19/2016 6:51:44 PM
```On Monday, December 19, 2016 at 7:51:53 PM UTC+1, Richard Heathfield wrote:
> On 19/12/16 18:38, Dexterr wrote:
> > On Monday, December 19, 2016 at 3:14:55 PM UTC+1, asetof...@gmail.com wrote:
> <snip>
> >> if(tokenise(series_connection, line))
> >>       allok;
> >
> > ----
> >
> > - NO, it does not work! Sorry.
>
> Yes, you have to be careful whose advice you follow.
>
> > This is my code:
>
> ...which is beginning to look quite clean and well-structured (although
> it isn't quite there yet).
>
> > #include <stdio.h>
> > #include <string.h>
> > #include <stdlib.h>
> >
> > #define FILENAME "netlist.txt"
> > #define NUM_FIELDS 4
>
> Good.
>
> >
> > typedef struct
> > {
> >   char *component;
> >   char *a_node;
> >   char *b_node;
> >   char *value;
> > }Components;
> >
> > int is_comment(const char *line);
> > //int tokenise();
>
> Remove the //, and add void. This will get rid of one of your compiler
> diagnostic messages.
>
> int tokenise(void);
>
> > void output(Components *ser_conn);
> >
> > char line[130] = "";
> > int line_number = 0;
> > Components *series_connection;
>
> Why have you put these at file scope?

-> Because I need it for the further calculations with data from this input file.
Here on UseNet I have noticed that people critisize my when I put something
in int main() function so I have got impression that good programmer are avoiding
to put small as possible declarations in int main function.

Maybe I am wrong.

> > int main(void)
> > {
> >   return 0;
> > }
> >
> > {
> >   FILE *fp = fopen(FILENAME, "r");
> >
> >   series_connection = malloc(sizeof *series_connection);
> >
> >   if(series_connection == NULL)
> >   {
> >   	fputs("[ERR] Out of memory", stderr);
> >   	exit(2);
> >   }
> >
> >   if(fp != NULL)
> >   {
> >   	while(fgets(line, sizeof line, fp) != NULL)
> >   	{
> >   	  ++line_number;
> >
> >       if(!is_comment(line))
> >       {
> >        if(tokenise(series_connection, line) == NUM_FIELDS)
>
> Okay, so we are expecting tokenise() to return the number of fields
> successfully parsed.
>
> >        {
> >
> >         // series_connection->component = strtok(line, " \t\n");
> >         // series_connection->a_node = strtok(NULL, " \t\n");
> >         // series_connection->b_node = strtok(NULL, " \t\n");
> >         // series_connection->value = strtok(NULL, " \t\n");
>
> That can all go.
>
> >
> >         output(series_connection);
> >
> >        }
> >       } // End of tokenise function - if condition
> >       else
> >       {
> >          fprintf(stderr, "Input error on line %d \n", line_number);
> >       }
> >     }
> >     // Close the file fp after reading and sorting
> >     fclose(fp);
> >   }
> >   else
> >   {
> >     fprintf(stderr, "Can't find %s.\n", FILENAME);
> >   }
> >   free(series_connection);
> >   series_connection = NULL;
> > } // End of readComponentFile function
> >
> > int is_comment(const char *line)
> > {
> >   return line[0] == '*';
> > }
> >
> >
> > int tokenise(Components *ser_con, const char *line)
>
> You can't make line const if you want to split the line into tokens.
> Removing const will get rid of your other compiler diagnostic message.
>
> > {
> >   ser_con->component = strtok(line, " \t\n");
> >   ser_con->a_node = strtok(NULL, " \t\n");
> >   ser_con->b_node = strtok(NULL, " \t\n");
> >   ser_con->value = strtok(NULL, " \t\n");
> >
> >   return ser_con->value != 0;
>
> Nope. Since your caller is expecting the number of fields successfully
> parsed, you want something like this:
>
> int tokenise(Components *ser_con, char *line)
> {
>    int successes = 0;
>
>    if((ser_con->component = strtok(line, " \t\n")) != NULL) ++successes;
>    if((ser_con->a_node = strtok(NULL, " \t\n")) != NULL) ++successes;
>    if((ser_con->b_node = strtok(NULL, " \t\n")) != NULL) ++successes;
>    if((ser_con->value = strtok(NULL, " \t\n")) != NULL) ++successes;
>
>    return successes;
> > }
> >
> >
> > void output(Components *ser_conn)
> > {
> >   if(ser_conn->component != NULL &&
> >      ser_conn->a_node != NULL &&
> >      ser_conn->b_node != NULL &&
> >      ser_conn->value != NULL)
>
> You already tested this in the caller. You can do it there, or you can
> do it here, but there's no need to do it in /both/ places.
>
> --
> Richard Heathfield
> Email: rjh at cpax dot org dot uk
> "Usenet is a strange place" - dmr 29 July 1999
> Sig line 4 vacant - apply within

Thanks Mr Richard on your response.

Now it works perfect. ;)

The idea is genial. I love it. Thanks for the comments and the explanations.
```
 0
Dexterr
12/19/2016 7:14:04 PM
```Dexterr: I see that you have a working version now, which is fine. You
might want to leave it there, especially if you have a deadline approaching!

The following notes will, I hope, teach you a little more about good
programming style, but if you're in a hurry to get on with the next bit
of the program you might want to save this article and come back to it
when you have more time. It is not essential at this stage.

On 19/12/16 19:14, Dexterr wrote:
> On Monday, December 19, 2016 at 7:51:53 PM UTC+1, Richard Heathfield wrote:
>> On 19/12/16 18:38, Dexterr wrote:
<snip>
>>>
>>> char line[130] = "";
>>> int line_number = 0;
>>> Components *series_connection;
>>
>> Why have you put these at file scope?
>
>  -> Because I need it for the further calculations with data from this input file.

But you can achieve that using parameters.

>      Here on UseNet I have noticed that people critisize my when I put something
>      in int main() function

Yes, ideally main() should be quite small. The point is to make the
structure of the program clear. Functions should, in general, be quite
short and self-contained.

Putting object definitions at file scope tends to make program structure
less clear. You will find debugging a lot easier if you don't have to
worry about the obscure interactions between functions that can

> so I have got impression that good programmer are avoiding
>      to put small as possible declarations in int main function.
>
>      Maybe I am wrong.

No, you're right, but good programmers /also/ try to keep function
inter-dependencies to a minimum.

>
>>> int main(void)
>>> {
>>>   return 0;
>>> }

There's not much point in burying everything in readComponentFile().

But you could do something like this:

int main(void)
{
Components *series_connection = malloc(sizeof *series_connection);
if(series_connection != NULL)
{
char line[130] = "";
FILE *fp = fopen(FILENAME, "r");
if(fp != NULL)
{
while(fgets(line, sizeof line, fp) != NULL)
{
if(! is_comment(line))
{
if(tokenise(series_connection,
line) == NUM_FIELDS)
{
output(series_connection);
}
}
}
fclose(fp);
}
else
{
fprintf(stderr, "Can't open %s for reading.\n",
FILENAME);
}
free(series_connection);
}
else
{
fprintf(stderr, "Out of memory.\n");
}
return 0;
}

The point of doing it this way is that main() now clearly demonstrates
the structure of the program, and this will help you if you need to
change the program in some way later on.

For example: at present, each iteration of the main program loop
invalidates the data collected on the previous iteration. This is not a
problem if you are processing the data line-by-line, as at present. But
it will /become/ a problem if, later on, you need to perform
calculations that require several lines of input. So, right now, no
change is needed. But if you needed to change the program later on, a
clear program structure will enable you to very quickly find the part
that needs changing.

--
Richard Heathfield
Email: rjh at cpax dot org dot uk
"Usenet is a strange place" - dmr 29 July 1999
Sig line 4 vacant - apply within
```
 0
Richard
12/19/2016 7:35:27 PM