1

I'm using the LXLE 14.04 distribution of Linux. I want to write a C program to read commands, interpret and perform them. I'd like the program to be efficient, and I do not want to use a linked list. The commands are operations on sets. Each set can contain any of the values from 0 through 127 inclusive. I decided to represent a set as an array of characters, containing 128 bits. If bit at position pos is turned on then the number pos is in the set and if the bit at position pos is turned off then the number pos is not present in the set. For example, if the bit at position 4 is 1, then the number 4 is present in the set, if the bit at position 11 is 1 then the number 11 is present in the set.

The program should read commands and interpret them in a certain way. There are a few commands: read_set, print_set, union_set, intersect_set, sub_set and halt.

For example, the command read_set A,1,2,14,-1 in the terminal will cause the reading of values of the list into the specified set in the command. In this case the specified set in the command is A. The end of the list is represented by -1. So after writing this command, the set A will contain the elements 1,2,14.

This is what I have so far. Below is the file set.h

#include <stdio.h>

typedef struct
{
    char array[16]; /*Takes 128 bits of storage*/
}set;



extern set A , B , C , D , E , F;

This is the file main.c

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

set A , B , C , D , E , F; /*Variable definition*/
set sets[6];
/*Below I want to initialize  sets so that set[0] = A set[1] = B    etc*/
sets[0].array = A.array;
sets[1].array = B.array;
sets[2].array = C.array;
sets[3].array = D.array;
sets[4].array = E.array;
sets[5].array = F.array;


void read_set(set s,char all_command[])
{
    int i, number = 0 , pos; 

    char* str_num = strtok(NULL,"A, ");
    unsigned int flag = 1; 
    printf("I am in the function read_set right now\n");

    while(str_num != NULL) /*without str_num != NULL get        segmentation fault*/
{
        number = atoi(str_num);
        if(number == -1)
            return;
        printf("number%d ",number);
        printf("str_num %c\n",*str_num);
        i = number/8;     /*Array index*/
        pos = number%8;  /*bit position*/
        flag = flag << pos;
        s.array[i] = s.array[i] | flag;

        str_num = strtok(NULL, ", ");

        if(s.array[i] & flag)
            printf("Bit at position %d is turned on\n",pos);
      else
         printf("Bit at position %d is turned off\n",pos);
    flag = 1;
   }

}


    typedef struct 
    {
         char *command;
         void (*func)(set,char*);
    } entry;

    entry chart[] = { {"read_set",&read_set} };

    void (*getFunc(char *comm) ) (set,char*)
    {
       int i;
       for(i=0; i<2; i++)
       {
           if( strcmp(chart[i].command,comm) == 0)
                return chart[i].func;
       }
       return NULL;
   }

    int main()
    {

       #define PER_CMD 256

        char all_comm[PER_CMD];   
        void (*ptr_one)(set,char*) =  NULL; 
        char* comm; char* letter;    

    while(  (strcmp(all_comm,"halt") != 0 ) & (all_comm != NULL))
    {
        printf("Please enter a command");
        gets(all_comm);
        comm = strtok(all_comm,", ");
        ptr_one = getFunc(comm);
        letter = strtok(NULL,",");
        ptr_one(sets[*letter-'A'],all_comm);
        all_comm[0] = '\0';
        letter[0] = '\0';
    }
    return 0;
}

I defined a command structure called chart that has a command name and function pointer for each command. Then I have created an array of these structures which can be matched within a loop.

In the main function, I've created a pointer called ptr_one. ptr_one holds the value of the proper function depending on the command entered by the user. The problem is, that since user decides which set to use,I need to represent the sets as some variable, so that different sets can be sent to the function ptr_one. I thought about creating an array in main.c like so

    set sets[6];
    sets[0] = A;
    sets[1] = B;
    sets[2] = C;
    sets[3] = D;
    sets[4] = E;
    sets[5] = F;

And then call the function ptr_one in the main function like this ptr_one(sets[*letter-'A'] , all_command). That way, I convert my character into a set.

The problem is that while writing the above code I got the following compile error:

error: expected ���=���, ���,���, ���;���, ���asm��� or ���attribute��� before ���.��� token

I also tried the following in the file main.c

     sets[0].array = A.array;
     sets[1].array = B.array;
     sets[2].array = C.array; 
     sets[3].array = D.array;
     sets[4].array = E.array;
     sets[5].array = F.array;

But I got this compile error expected ���=���, ���,���, ���;���, ���asm��� or ���attribute��� before ���.��� token

I know similar questions have been asked, by they don't seem to help in my specific case. I tired this set sets[6] = { {A.array},{B.array},{C.array},{D.array},{E.array},{F.array} } too but it did not compile.

What's my mistake and how can I initialize sets so that it holds the sets A though F?

Cœur
  • 37,241
  • 25
  • 195
  • 267
Tree
  • 145
  • 1
  • 13
  • `getFunc` can return NULL, so you must check its return value before to use `ptr_one`. – LPs Jan 12 '17 at 08:01
  • Do you really get the question-mark-in-a-black-diamond marks when you compile? What's going on there? You can't have the 6 assignments outside the body of a function. If you did do the assignments inside a function, then you'd have a copy of `A`..`F` at the time of assignment, so subsequent changes to `A`..`F` would not be reflected in `sets[0..6]`. You might use `set *sets[6] = { &A, &B, &C, &D, &E, &F };` but you should probably stick with one or the other — I'd probably go with an array of sets rather than an array of pointers to sets. – Jonathan Leffler Jan 12 '17 at 08:02
  • `letter = strtok(NULL,",");` is UB as first call. – LPs Jan 12 '17 at 08:03
  • Thank you. Yes I get these question-mark-in-a-back-diamond marks. Why cannot I have 6 assignment outside the body of a function? I'm still not sure how to solve this. Should I initialize sets in each function? As I understand it, if I define sets inside functions, the definition would be local to the function, but I want sets to hold A though F permanently. How can I achieve this? Thanks! @ Jonathan Leffler – Tree Jan 12 '17 at 08:28
  • Thanks a lot! I have just added a test to check the return values of getFunc before actually using ptr_one. As to strtok, I'm not sure, why is this an undefined behavior? Thank you very much! @LPs – Tree Jan 12 '17 at 08:34
  • To get the diamonds, you must be running into a locale mismatch with your compiler in some shape or form. It is probably a Unicode punctuation (likely curly quotes) in UTF-8 being mishandled. However, that's mostly incidental. – Jonathan Leffler Jan 12 '17 at 08:37
  • You can only define and initialize variables outside functions; you cannot have executable statements like assignments outside functions. Note that `int i = 3;` is an initialization. Omit the `int` and it is an assignment. You can define `A`..`F` outside the function; that's no problem. You can define `set sets[6];` (or `set *sets[6];`) outside the function; that's no problem. You simply can't have the 6 assignments outside the function. – Jonathan Leffler Jan 12 '17 at 08:39
  • Note that [`gets()` is too dangerous to be used — ever!](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) – Jonathan Leffler Jan 12 '17 at 08:43
  • Thanks for the quick reply. How can I initialize the array sets the right way? – Tree Jan 12 '17 at 08:43
  • @LP: I think that there is a call to `strtok()` with a non-null argument in `main()` before the code gets into `read_set()` so that the first call in the function is not necessarily undefined behaviour. It is just rather fragile. What is undefined behaviour is the loop in `getFunc()` which iterates over two elements of a one-row element array. That's not allowed. – Jonathan Leffler Jan 12 '17 at 08:45
  • It depends on what you want to do. I showed you how you could initialize an array of pointers. If you simply have an array of sets, you don't need to initialize them; they'll be initialized to 'all bytes zero' anyway. If you want some other initialization, you'll need to define what you want to do — and when you know what you want to do, you'll probably be able to do it, but until you know, you won't. And, until you know, we won't know either so we won't be able to help you. There's no right or wrong answer unless the compiler complains — you have to decide what's correct for your design. – Jonathan Leffler Jan 12 '17 at 08:48
  • @JonathanLeffler Yes, for sure if the posted code is not the whole code of main. – LPs Jan 12 '17 at 08:50
  • Thanks for helping me and replying so quickly! I changed the loop in getFunc to iterate over one element only. As to gets, I got this compile warning: gets() is too dangerous to be used, and read about it a lot, but didn't really understand how to prevent it. If I understand well, fgets might prevent this but it does not seem to me like the right choice here as I do not know how many input lines should be read. Thanks! @– Jonathan Leffler – Tree Jan 12 '17 at 09:04
  • I know what I want to do. I want to have a variable sets which is an array of sets to hold the sets A though F are global variables, so that I can convert the character entered by the user (for example 'A') into a set so that I can perform the commands on the specified set. (for example sets[*letter-'A'] while *letter = 'A' gives sets[0], and sets[0] = A which is the set A, not the character) . So I know what I wan to do, I just do not know how to do it correctly. Thanks a lot1 – Tree Jan 12 '17 at 09:14
  • 1
    You should use `for(i=0; i – LPs Jan 12 '17 at 09:14
  • Thank you, it really helped me! @LPs – Tree Jan 12 '17 at 09:19
  • Actually, what loop? @LPs – Tree Jan 12 '17 at 09:31
  • The `getFunc` one. – LPs Jan 12 '17 at 09:32
  • Ah, I got it, Thank you! @LPs – Tree Jan 12 '17 at 09:34

0 Answers0