Reputation: 243
Haven't found anything answering my question, so here goes:
I want to return an integer from a function to my main for further use, specifically it's a an add()
function that creates a list from entries in a text file. The integer I want to return is called error, is declared as 0 at the beginning of the function and changes to 1 when a condition is met (in my case, if any character other than a-z, A-Z, - and ' ' is found). If this condition is met, I want to return error (as 1) to the main function, otherwise i return it as 0. In my main I then have an if statement that checks if error is 1 to then print an error message and return 1. Is that possible? I've tried a few things but it doesn't work, if I initialize the error variable as 0 in my main, shouldn't the add function change it to one in case of my error condition? I don't want to use global variables and only want to implement the add function into main as a last resort.
Sorry if this is complete nonsense, I am very much a beginner.
int add(char line[])
{
struct node *newnode = (struct node *) malloc(sizeof(struct node));
struct node *walker = newnode;
strcpy(newnode->name, line);
int check = 0;
int error = 0;
while(line[check] != '\n')
{
if(line[check] == '!')
{
error = 1;
return error;
}
check++;
}
. //Here is just the creation of the list elements
. //If the functions reaches end, it returns error with 0 as value
.
}
And the main:
int main()
{
FILE *fp;
char line[33];
int error = 0;
fp = fopen("test.txt", "r");
if(!fp)
{
printf("Error.");
return 0;
}
while(fgets(line, 33, fp) != NULL)
{
add(line);
}
fclose(fp);
if(error == 1)
{
printf("error");
return 1;
}
// ...
}
EDIT: Ok, I've made it work, and since a few people basically had the right solution for me, I wanted to say thanks here! Don't know if I can choose multiple answers as correct.
Upvotes: 2
Views: 3738
Reputation: 1085
A side answer to comments. Became a bit long for a new comment.
(This is regarding while(line[check]) != '\n') {
)
fgets
is OK. But fgets
quit reading once it reaches a newline or have read 32 bytes.
It does not append a newline to the end of data.
That \n
at the end is only there if it was inside the bounds of current location in file. What it do every time is append a null, as in 0x00
as last byte - within length of read data. AKA C-string termination.
That is:
buf[4];
line 'a\n' => buf = {'a', '\n', 0x00}
line 'ab\n' => buf = {'a', 'b' , '\n', 0x00}
line 'abc\n' => buf = {'a', 'b' , 'c' , 0x00}
Put another way. That newline in buf is not something fgets
append, - but is
part of the read data that also triggers a stop in read. Thus you have:
fgets stop reading if:
IF lenght - 1 bytes read
OR IF read \n
OR IF end of file
Also; if a line is more then 32 bytes next read will continue where it left off, not on next line.
That gives:
data:
abc
defghijklmno
pq
rstuv
Sample code:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp;
char *fn = "sample.txt";
char buf[4];
int i = 0;
if (argc > 1)
fn = argv[1];
if ((fp = fopen(fn, "r")) == NULL) {
fprintf(stderr, "Unable to open '%s` for reading.\n", fn);
return 1;
}
while(fgets(buf, 4, fp) != NULL) {
fprintf(stdout, "%2d: @%s@\n", i++, buf);
}
fclose(fp);
return 0;
}
Result:
0: @abc@
1: @
@
2: @def@
3: @ghi@
4: @jkl@
5: @mno@
6: @
@
7: @pq
@
8: @rst@
9: @uv
@
What happens in your code, the while loop, is that if there are no \n
or !
in line
it keeps advancing beyond the memory area where line
resides. Either it result in a
segfault or it finds one of the two and aborts - giving you false positives if say:
char line[4]; read 'abcd'
MEMORY ADDRESS REF VALUE
0xf00 line[0] a
0xf01 line[1] b
0xf02 line[2] c
0xf03 line[3] 0x00
0xf04 <unknown> z
0xf05 <unknown> x
0xf06 <unknown> 0x08
0xf07 <unknown> A
0xf08 <unknown> f
0xf09 <unknown> 0xfd
0xf0a <unknown> !
0xf0b <unknown> g
By this your function would return error because it kept reading until address 0xf0a
where it found !
– but this is not part of line
.
By this also rename line
to buf
or the like as it is confusing in the code (perhaps).
And, only as a suggestion, consider returning 0
on success and != 0
on error
as that is the convention by many functions in same format.
A function named is_ok(var)
, would be logical to return 1 for true and 0 for false,
but a function add(var)
is more logical to return != 0
on error – as in error code.
EDIT to comment:
Yes. A normal way could be something like:
int i = 0;
while (buf[i] && buf[i] != '\n') {
if (!isalpha(buf[i++]))
return 1;
}
Or the more clearer, but IMHO not needed as if one are normalized to C it one intuitively read it as this:
while (buf[i] != 0x00 && buf[i] != '\n') {
...
isalpha() is part of ctype.h
, but if you know it is always going to be ASCII
it is easy enough to write yourself. Also read this perhaps.
Upvotes: 1
Reputation: 5389
The variables you have in add()
and main()
are local variables. This means that the values they contain cannot be used outside the respective functions. So when add()
returns a value, you need to have a variable in main()
to collect that. So,
while(fgets(line, 33, fp) != NULL)
{
/* Here when the add returns 1 or 0, the value is collected
* by the "error" variable of main function */
error = add(line);
if( error == 1 ) break ; /* Its Simple :-) */
/* Once add() returns, you will break from the while loop
will continue with the main() instructions ahead */
}
Upvotes: 1
Reputation: 548
In the function add(), change the line
if(line[check] == '!')
to
if(!ok(line[check]))
and write the function ok so that it checks if the provided argument isn't a letter of English alphabet or a space. Now you just just check if your line contains !. Maybe that's a mistake.
You can write ok like this:
int ok(char ch){
return (ch>='A' && ch<='Z') || (ch>='a' && ch<='z') || ch==' ';
}
In the main, you should have something like this:
while(fgets(line, 33, fp) != NULL)
{
error=add(line);
if(error==1) ... handle error ...
Upvotes: 1
Reputation: 5239
int main()
{
FILE *fp;
char line[33];
int error = 0;
This error variable in main is different from the one defined in add
int check = 0;
int error = 0;
When you call error in main, that variable local to main is called which is still unaltered.
The change to error
in add
is local to that function. Changes in that variable is not reflected in error
in main.
You have to something like int error = add(line);
if(error)
in main
Upvotes: 0
Reputation: 324
I think you are in the right direction just inside the while you don't use the value that add() function returns.
You have to assign that function to the error like error = add(line);
and then you can check if that is 1
so you return.
Hope this helps of course the checking has to be don inside the while as every time the value changes and thus you might loose the value 1
. With error = add(line);
inside the while , variable error takes new value in every loop.
Upvotes: 0
Reputation: 5132
you seem to have two variables called error
, one in add()
and another in main()
, they are different variables!
you need at least to change
add(line);
to
error = add(line);
if (error != 0)
break;
Upvotes: 2