-1

I wrote this function to search a text file (which currently just says "cube") for one of the words and then call the corresponding function. However, I am getting the 'Error: No Function Found.' message.

Could anyone help me in identifying my problem?

void read(){
    const char cube[4] = "cube";
    const char cone[4] = "cone";
    const char sphere[6] = "sphere";
    const char cylinder[8] = "cylinder";

    char line[1024] ;
    FILE* fp = fopen("instructions.txt", "r") ;
    while (fgets(line , sizeof(line) , fp )!= NULL)
    {
        if (strstr(line , cube)!= NULL){
            void cube();
        }
        else if (strstr(line , cone)!= NULL){
            void cone();
        }
        else if (strstr(line , sphere)!= NULL){
            void sphere();
        }
        else if (strstr(line , cylinder)!= NULL){
            void cylinder();
        }
        else {
            printf("Error: No Function Found./n");
        }
    }
    fclose(fp);
    free(line);
    return;
}
wohxela
  • 35
  • 6
  • which function is reporting the error? – Woodrow Barlow Apr 01 '21 at 13:10
  • maybe there was a line that didn't have cube or cone or sphere or cylinder in it? Note that when you *do* find cube or cone or sphere or cylinder, you don't do anything. (`void cube();` doesn't do anything) and then you just go to the next line – user253751 Apr 01 '21 at 13:11
  • 5
    `const char cube[4] = "cube"` is not a string. It is not null terminated. Use `const char cube[] = "cube"` and let the compiler determine the size correctly. (hint: it should be at least 5) – William Pursell Apr 01 '21 at 13:11
  • @WoodrowBarlow so none of the if statements are being fulfilled as the my “No Function Found” statement is being printed, meaning that none of the shape functions are being called :/ – wohxela Apr 01 '21 at 13:12
  • @user253751 to test the function, the text file only has the word “cube” in it at the moment – wohxela Apr 01 '21 at 13:15
  • What is `void cube();` supposed to be? – William Pursell Apr 01 '21 at 13:16
  • I wouldn't call your function `read()` because that's a standard one on POSIX/Unix/Linux/etc. OSes and your own definition is likely to cause issues. – Shawn Apr 01 '21 at 13:17
  • You don't check if `fopen` fails. – Jabberwocky Apr 01 '21 at 13:17
  • 3
    OT : `free(line);` is very wrong. – anastaciu Apr 01 '21 at 13:17
  • @WilliamPursell cube() is a previously defined function that prints some code to another file - these functions work perfectly so it’s the if statements that have a problem – wohxela Apr 01 '21 at 13:18
  • `void cube();` is a function declaration, not a function call. `cube();` is a function call. – Ian Abbott Apr 01 '21 at 13:19
  • Those functions might work perfectly, but you have to call them for that to happen, not just declare that they exist... – Shawn Apr 01 '21 at 13:19
  • @Jabberwocky fopen doesn’t fail - I tested it by printing the frets function and the text from the file was printed – wohxela Apr 01 '21 at 13:19
  • 1
    @alexandrahowes OK, but still this check needs to be done, because if you don't and the `fopen` function fails you're introuble. – Jabberwocky Apr 01 '21 at 13:21
  • @Shawn am I not calling them properly? – wohxela Apr 01 '21 at 13:21
  • 2
    No... no you're not. You're not calling them at all. – Shawn Apr 01 '21 at 13:22
  • You're making a bunch of other function calls in your code, but not those for some reason. Do you see the difference between `fopen()`, `strstr()` etc. and the problem ones? – Shawn Apr 01 '21 at 13:23
  • @Shawn when I call the functions cube() etc. as I would normally, I get an error message that says “called object ‘cube’ is not a function or function pointer” – wohxela Apr 01 '21 at 13:33
  • Have you actually defined a function called `cube` for your code to call? – Ian Abbott Apr 01 '21 at 13:36
  • 1
    As Lundin pointed out in an answer, if you remove the function prototype, you now have `cube` being a char array, which obviously can't be called like a function. – Shawn Apr 01 '21 at 13:36
  • If you do not want to rename any variables, you can keep the declaration `void cube();` (or preferably, `void cube(void);`) and add the function call `cube();` after it. – Ian Abbott Apr 01 '21 at 13:40
  • If using gcc or clang, add `-Wshadow` to your warning options (You are compiling with warnings turned on, right? `-Wall -Wextra` if not) and it'll help point out things like that. – Shawn Apr 01 '21 at 13:43

5 Answers5

1
const char cube[4] = "cube";
strstr("foobar", cube);  /* undefined behavior */

In the above, cube is not a null-terminated string, so strstr will cause undefined behavior when it attempts to read past the bounds of the array. You need 5 characters to store a 4 character string. The best way to avoid this mistake is to use:

const char cube[] = "cube";

or const char *cube = "cube";

Also, your attempts to invoke the function cube are failing.

if (strstr(line , cube)!= NULL){
    void cube_f();  /* Declare a function, using a non-standard compiler extension */
    cube_f();   /* Call the function */
}

But note that you have a name clash, and cube cannot be both the name of a function and a local variable. I've added a suffix to the name to prevent that name collision. If cube is previously defined for you, you should probably change the name of the local variable instead.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
1

All C-style string must be terminated with ‘\0’. The corresponding code must like:

const char* cube= "cube";
const char* cone = "cone";
const char* sphere = "sphere";
const char* cylinder = "cylinder";

cube is const char pointer. BTW, “cube” generally stored in your program's code segment or on the stack That's up to the compiler. Either way, it points to a null-terminated array of characters.

mariolu
  • 624
  • 8
  • 17
1

You probably want this:

void read() {
    const char cube_str[] = "cube"; // let the compiler determine the length
    const char cone_str[] = "cone"; // which also ensures the strings are NUL terminated
    const char sphere_str[] = "sphere";
    const char cylinder_str[] = "cylinder";

    char line[1024] ;
    FILE* fp = fopen("instructions.txt", "r") ;
    if (fp == NULL)  // check for error
    {
       // display error message and abort
    }
    while (fgets(line , sizeof(line) , fp ) != NULL)
    {
        if (strstr(line , cube_str)!= NULL){
            cube();    // call function instead of declaring it
                       // void cube();  is just a declaration, it 
                       // doesn't call the funtion
        }
        else if (strstr(line , cone_str)!= NULL){
            cone();
        }
        else if (strstr(line , sphere_str)!= NULL){
            sphere();
        }
        else if (strstr(line , cylinder_str)!= NULL){
            cylinder();
        }
        else {
            printf("Error: No Function Found./n");
        }
    }

    fclose(fp);
    // remove this line:  free(line);
    // you can only free pointers returned by malloc and friends
    return;
}
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • I get an error message when the function is called as cube() for example. It says “called object ‘cube’ is not a function or function pointer” – wohxela Apr 01 '21 at 13:31
1

Basically, it boils down to this: when writing C code, you cannot take a chance at what something does or how something works. You must actually know what every single line of code that you write does. There is no trial & error way of learning, because some things might seem to work while they are actually dormant bugs waiting to crash your program.

I find the following problems in your code:

  • No #include of libraries. I assume you just left this out on purpose.
  • void read() Empty parenthesis is obsolete style in C (but perfectly fine in C++). When coding C, you should always do void read (void).
  • cube[4] = "cube" Strings in C are null terminated. You don't allocate enough room. Study this: How should character arrays be used as strings?
  • void cube(); etc. I have no idea what you think this does, call a function? That's not how you call a function. Furthermore, since you have a local scope variable named cube you get a naming collision. So the function would have to use a different name.
  • free(line); You are not allowed to use free on memory that you didn't allocate with malloc. Simply remove this line.
  • return; isn't necessary in a function returning void.
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • I have included the libraries however this is just one function within my program; the void has been removed - it was a mistake (sorry!) I’m just getting an error that says it’s not a function or function pointer... – wohxela Apr 01 '21 at 13:35
  • Also I have removed the 4 etc as I realise that’s silly, I’m new to C and will make a few mistakes along the way..! Free(line) was accidentally left there since I was using malloc. As for the return; guidance - that’s very useful to know, thank you! – wohxela Apr 01 '21 at 13:37
1

Others have demonstrated some syntax errors in your example, but nobody has addressed the logic error. Your code (sans syntax errors) reads each line of the file, and reacts if that line contains certain substrings.

That means, if a line of text contains the word "iconegraphy" (sic), this will trigger your "cone" handling logic. Furthermore, if a line contains both the word "cube" and "cone", then only your cube logic will fire.

To overcome this, you will need to split the line into individual words. You can accomplish this by scanning whitespace and processing the words one at a time.

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

// warning, this code is untested, but should send you in the right direction

char *find_word(char *input)
{
    while (isspace(input) && *input != '\0')
    {
        input += sizeof(char);
    }
    return input;
}

char *find_whitespace(char *input)
{
    while (!isspace(input) && *input != '\0')
    {
        input += sizeof(char);
    }
    return input;
}

void process_word(char *word, size_t len)
{
    if (strncmp(start, "cube", len) == 0)
    {
        // do something
    }
    else if (strncmp(start, "cone", len) == 0)
    {
        // do something
    }
    else if (strncmp(start, "sphere", len) == 0)
    {
        // do something
    }
    else if (strncmp(start, "cylinder", len) == 0)
    {
        // do something
    }
}

int main(int argc, char *argv[])
{
    FILE *fp = fopen(argv[1]);
    char line[1024];

    while (fgets(line, sizeof(line), fp) != NULL)
    {
        char *cursor = line;
        while (*cursor != '\0')
        {
            char *start = find_word(line);
            char *end = find_whitespace(start);
            process_word(start, end - start);
            cursor = end;
        }
    }
}
Woodrow Barlow
  • 8,477
  • 3
  • 48
  • 86