Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

[C++] COMPILER ERROR: error: expected ']' before ';' token

  1. Nov 9, 2013 #1
    [C++] COMPILER ERROR: "error: expected ']' before ';' token"

    I'm getting 3 errors on the line

    Code (Text):
    usi bA_indx_val = _booArr[indx/USI_BITS];
    denoted in my code.

    error: expected ']' before ';' token
    error: expected primary-expression before ']' token
    error: expected ';' before ']' token


    Can't figure out what's going on. Any help greatly appreciated.

    I'm trying to make a dynamic bitset. My code is incomplete because I'm checking for errors as I write it and I'm stuck right now.

    Code (Text):


    #include <iostream>
    #include <limits.h>
    #include <assert.h>

    typedef unsigned short int usi;

    #define USI_BITS (sizeof(usi)*CHAR_BIT);

    int main (int argc, char* const argv[]) {
       
       
        return 0;
    }


    class BitPack {

        public:
        BitPack(int);
        ~BitPack();
        bool getVal(int);
        int getSize();
        void setVal(int, bool);
       
        private:
        usi* _booArr;
        int _booArrLen;
        int _numBoos;
        usi _pow2(int);
       
    };

    BitPack::BitPack(int sz) {
            assert (sz > 0);           
            _numBoos = sz;
            _booArr = new usi[_numBoos/sizeof(usi)+(_numBoos % sizeof(usi) ? 1 : 0)];
            _booArrLen = sizeof(_booArr)/sizeof(usi);
            for (int i = 0; i < _booArrLen; ++i)
               _booArr[i] = 0;
    }

    BitPack::~BitPack() {
        delete[] _booArr;
    }

    bool BitPack::getVal(int indx) {
        assert (indx > 0); 
        usi bA_indx_val = _booArr[indx/USI_BITS]; // ERROR
        int rmndr_bits = bA_indx_val % USI_BITS;
        for (int i = 0; i < rmndr_bits; ++i)  
            bA_indx_val /= 2;
        return (bA_indx_val % 2 ? true : false);
    }

    int BitPack::getSize() {
        return (_numBoos);
    }

    void BitPack::setVal(int indx, bool val) {
        assert (indx > 0);
        /*
               I'm in the middle of writing this right now.
        */
    }

    usi BitPack::_pow2(int n) {
        assert (n >= 0);
        usi prdct = 1;
        for (int i = 0; i < n; ++i)
            prdct *= 2;
        return prdct;
    }

     
     
  2. jcsd
  3. Nov 9, 2013 #2

    Borek

    User Avatar

    Staff: Mentor

    Try to replace

    Code (Text):
    #define USI_BITS (sizeof(usi)*CHAR_BIT);
    with

    Code (Text):
    #define USI_BITS (sizeof(usi)*CHAR_BIT)
     
  4. Nov 9, 2013 #3

    jim mcnamara

    User Avatar

    Staff: Mentor

    The whole content of a #define gets substituted every time you reference it.
     
  5. Nov 9, 2013 #4

    AlephZero

    User Avatar
    Science Advisor
    Homework Helper

    #define is a compiler directive, not a C++ statement. It doesn't need a terminating semicolon. But you are not the first person to forget that, nor will you be the last!

    If all else fails trying to understand this sort of error, use the compiler option that shows you the "expanded" source code after preprocessing.
     
  6. Nov 9, 2013 #5

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Have you heard the phrase "coffee stain on the flip-down trays"? An airline CEO, while inspecting how his company handled airplane turnover, walked through the cabin and flipped down one of the tray tables. He saw coffee stains on the tray table. To the crew this was no big deal. They saw their job as cleaning out the cabin quickly to make way for the next set of passengers. The CEO saw it differently: "Coffee stains on the flip-down trays mean [to the passenger] that we do our engine maintenance wrong." It might be irrational, but those coffee stains on the tray tables mean passengers will look for another airline the next time they fly.

    Your code has *lots* of coffee stains on the tray tables. Suppose you send code to be evaluated by an interviewer for some job. Your code might work, but those coffee stains on your code mean your job application will be filed circularly. (The circular file is the can everyone has next to their desk into which trash paper is discarded.) Don't take that chance. Get rid of those coffee stains.
    • No comments!
      The only comment in your code is the one that says "I'm in the middle of writing this right now." Get into the habit of commenting all key components. The commentary should be one of the first things you write, not the last.

      Each file should have a comment at the start of the file that addresses why the file exists, who wrote it, and who owns it. Here's a simple file header for your file:
      Code (Text):

      /**
       * @file bitpack.hh
       * Defines the class BitPack and ancillary functions.
       *
       * @author Jamin2112
       * @copyright GNU Public License.
       */
       
      Each class should have a comment saying why the class exists, how to use it *in brief terms*. Example:
      Code (Text):

      /**
       * Class BitPack represents a fixed-size sequence of N bits.
       * BitPacks can be accessed and manipulated at the bit level ...
       */
      class BitPack {
         ...
      };
      Each member function should have a comment that briefly describes what it does, the arguments, and the return value (if it has one). Example:
      Code (Text):

      class BitPack {
         ...

         /**
          * Non-default constructor. All bits in the bit array are initialized to zero.
          * @param nbits Number of bits in the bit array.
          */
         BitPack(int nbits);

         ...
      };
      Each data member should have a comment saying why it exists. Example:
      Code (Text):

      class BitPack {
         ...

         /**
          * The bit array.
          * @note This is allocated and deleted per the RAII idiom.
          */
         usi* _booArr;

         ...
      };
      Regarding the comments I wrote: I'm using doxygen comments in the above. This is becoming the de facto standard for C++ documentation. The doxygen engine parses your comments and creates API documentation in html, LaTeX, and man page form. It's free.

      BTW, I used the acronym RAII above. The person who is reviewing your code knows (or should know) what that means. You should, too.


    • #include <limits.h> and #include <assert.h>
      This is C++. Use the C++ headers. You should have #included <climits> instead of <limits.h>, <cassert> instead of <assert.h>.


    • Macros.
      Eschew macros in C++. You could have used a const static class member for this.


    • Inconsistent indentation in how you indented public and private.
      My preference is to outdent public, protected, and private so they have the same indentation as the class statement. I do the same with case labels. I outdent anything that looks like a label. That's my preference, yours may vary. Whatever rule you do use, be consistent. Lack of consistency is a big coffee stain.


    • You have tabs in your source code. Don't do that.
      You can use tabs while you are typing in your code if you can set your editor or IDE to automatically translate the tabs you type into the appropriate number of spaces.

      Suppose you send your code to an interviewer for some job. She almost certainly will use a different editor with different tab settings than do you. Because your files contain tabs, when she opens your file she may well see garbage. This means your job application is also garbage. Don't take that chance.


    • You aren't following the Rule of Three.
      The Rule of Three dictates that if you have a non-trivial destructor, copy constructor, or assignment operator, you almost certainly need all three. You have a non-trivial default constructor that allocates data. You are starting to follow RAII in that you do have a destructor, but you don't have a copy constructor or assignment operator. This will bite you someday. Get in the habit of declaring a copy constructor and assignment operator as soon as you declare a destructor.


    • Multiplication and division by 2 (in a loop!) instead of using the bit operators and bitmasks.
      This is worse than a coffee stain on the tray table. It's a whole cup of coffee that was spilled on the tray table and then dripped onto and stained the carpet. This is unacceptable code. Use the bit operators (bitwise-and, bitwise-or, left shift, right shift) when you are dealing with bits.
     
    Last edited: Nov 9, 2013
  7. Nov 9, 2013 #6


    • Alright. I will.


      Will do. I really just started writing this and I considered comments to be the finishing touches. Plus, I'm probably going to change a lot of my procedures.

      Will do.

      Will do.

      Good point. Will do.

      I'm going to have to remember this.

    Yea, I figured that what I did made me look like a rank amateur lol.
     
  8. Nov 10, 2013 #7
    So ..... How do I use a bit operator to mod by 2? I know how to multiply and divide by 2.
     
  9. Nov 10, 2013 #8

    Mark44

    Staff: Mentor

    x & 1 will be 1 if x is odd and will be 0 if x is even.
     
  10. Nov 10, 2013 #9
    Alright, guys. It's getting better. Not perfect yet, but improved, I think.

    Code (Text):


    #include <iostream>
    #include <limits.h>
    #include <assert.h>

    typedef unsigned short int usi;

    class BitPack {
       
    public:
        BitPack(int);
        ~BitPack();
        BitPack(const BitPack&);
        bool getVal(int);
        int getSize();
        void setVal(int, bool);
        void print();
       
    private:
        // class constant for # of bits in an unsigned short int:
        const static int _USI_BITS = sizeof(usi)*CHAR_BIT;
        usi* _booArr;  
        int _booArrLen;
        int _numBoos;
       
    };

    BitPack::BitPack(int sz) {
        assert (sz > 0);           
        _numBoos = sz;
        _booArrLen = _numBoos/_USI_BITS + (_numBoos % _USI_BITS ? 1 : 0);
        /*         = # of elements needed in an array of unsigned short ints
                     to have enough bits to store the number of booleans needed */
        _booArr = new usi[_booArrLen];
        for (int i = 0; i < _booArrLen; ++i)
            _booArr[i] = 0;
    }

    BitPack::~BitPack() {
        delete[] _booArr;
    }

    BitPack::Bitpack(const BitPack& other) {
       
    }

    bool BitPack::getVal(int indx) {
        assert (indx >= 0);                
        usi bA_indx_val = _booArr[indx/_USI_BITS];
        bA_indx_val >>= (indx % _USI_BITS);
        return ((bA_indx_val & 1) ? true : false);
    }

    int BitPack::getSize() {
        return (_numBoos);
    }

    void BitPack::setVal(int indx, bool valset) {
        assert (indx >= 0);          
        bool curval = getVal(indx);
        if ((curval == true) && (valset == false)) {
            _booArr[indx/_USI_BITS] &= ~(1 << (indx % _USI_BITS)); // changes the
        } else if ((curval == false) && (valset == true)) {      
            _booArr[indx/_USI_BITS] |= (1 << (indx % _USI_BITS));  
        }
    }
                   
    void BitPack::print() {
    /* prints out all the bools as a stream of 0's and 1's (not including the possible
       extra padding in the array of unsigned short ints) */   
        int i = 0;
        usi thisval;
        while (i < _booArrLen - 1) {
            thisval = _booArr[i];
            for (int j = 0; j < _USI_BITS; ++j) {
                std::cout << (thisval % 2 ? '1' : '0');
                thisval >>= 1;
            }
            i++;
        }
        thisval = _booArr[i];
        int rmndr = _numBoos % _USI_BITS;
        if (rmndr == 0)
            rmndr = 16;
        for (int j = 0; j < rmndr; ++j) {
            std::cout << (thisval % 2 ? '1' : '0');
            thisval >>= 1;
        }
        std::cout << "\n";
    }

    int main (int argc, char* const argv[]) {
       
        BitPack bp(18);
        bp.setVal(1,true);
        bp.setVal(17,true);
            bp.print();
        return 0;
       
    }


     
     
  11. Nov 11, 2013 #10

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    That's improved. At least you are using bit operators.

    You still have tabs in your code, and still no comments.


    The modern way to write code is to write the test code first -- before you write *any* of the actual code. This means the tests will initially fail, massively. The code won't even compile at first, let alone link or execute. That is deemed to be a good thing in test driven development. You have taken the first step toward "debugging the blank sheet of paper." (Your boss says "This sheet of paper has a complete design for your system. There's one minor bug: The page is blank. Fix that bug!")

    You solve this problem one step at a time. The tests dictate the public interfaces. You now know what the class is supposed to do in a broad sense, what each public function is supposed to do. This gives enough information to write the public part of the class definition, along with rudimentary documentation. Now your test code will successfully compile! Phase I complete. It won't link, of course; that's the next step in the debugging a blank sheet of paper process.


    Back to your code. I that see you've asked on another site how to create a copy constructor. Presumably you now know how to do that. The next step in the Rule of Three is to write an assignment operator. There are lots of gotchas with the assignment operator. Here's a particularly nasty one:
    Code (Text):

    BitPack bit_pack = BitPack(42);
    bit_pack = bit_pack;
     
    Who would do that? It doesn't matter that this is nonsense. Someday, someone will abuse your beautiful code just like that, if not worse. You need to defend against it. You can find all kinds of advice on the web on dealing with the self-assignment problem.

    Another gotcha: You have dynamically allocated data in your BitPack class. Your assignment operator has to free the existing bitset, allocate a new one sized per the source object's bit set, and copy the contents of the source object's bitset into this newly allocated one. This is a royal pain.

    There's a rather nifty solution that eliminates all this pain, the copy and swap paradigm. The prototype for a typical assignment operator is ClassName & operator=(const ClassName & source); With copy-and-swap you strike out the "const" and "&": The prototype is ClassName & operator=(ClassName source); You are receiving a copy of the source object rather than a reference or pointer to the source object. The implementation of the assignment operator is brutally simple with the copy-and-swap paradigm:
    Code (Text):

    ClassName & ClassName::operator= (ClassName source) {
       swap (*this, source);
       return *this;
    }
     
    Here's how it works. The assignment operator receives a temporary that is a complete copy of object. That the argument is declared as ClassName source rather than ClassName & source ensures that this is a temporary. The copy constructor (you've written a good copy constructor, right?) will populate this temporary with a complete copy of the true source object. The destructor is called on this temporary when it goes out of scope. This happens at the semicolon in object_to_receive_copy = object_to_be_copied; Your copy-and-swap assignment operator takes advantage of this fact. Exchange (swap) all member data with that of the temporary and voila! you have a copy of the true source, and all the old data is properly taken care of.

    All that's left is to write this magical swap function. That's easy!
    Code (Text):

    #include <algorithm>

    void swap (ClassName & a, ClassName & b) {
       std::swap (a.data_member_1, b.data_member_1);
       std::swap (a.data_member_2, b.data_member_2);
       ...
       std::swap (a.data_member_n, b.data_member_n);
    }
    One last point: Class ClassName needs to declare this swap function as a friend function. That's one more line of code in your class definition. Easy.
     
  12. Nov 11, 2013 #11
    Alright. I'll post my almost-finished product.
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: [C++] COMPILER ERROR: error: expected ']' before ';' token
Loading...