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

In summary: The bit array is allocated and deleted with the "RAII idiom." This means that BitPack will not crash if the bit array goes out of scope.In summary, your code has errors that prevent it from compiling. You need to fix the errors and submit your code for evaluation.
  • #1
Jamin2112
986
12
[C++] COMPILER ERROR: "error: expected ']' before ';' token"

I'm getting 3 errors on the line

Code:
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:
#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;
}
 
Technology news on Phys.org
  • #2
Try to replace

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

with

Code:
#define USI_BITS (sizeof(usi)*CHAR_BIT)
 
  • Like
Likes 1 person
  • #3
The whole content of a #define gets substituted every time you reference it.
 
  • #4
#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.
 
  • #5
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:
    /**
     * @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:
    /**
     * 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:
    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:
    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:
  • #6
D H said:
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.


  • Alright. I will.

    [*]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:
    /**
     * @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:
    /**
     * 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:
    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:
    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.


    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.

    [*]#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.

    Will do.

    [*]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.

    Will do.

    [*]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.

    Good point. Will do.

    [*]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.

    I'm going to have to remember this.

    [*]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.

Yea, I figured that what I did made me look like a rank amateur lol.
 
  • #7
So ... How do I use a bit operator to mod by 2? I know how to multiply and divide by 2.
 
  • #8
x & 1 will be 1 if x is odd and will be 0 if x is even.
 
  • #9
Alright, guys. It's getting better. Not perfect yet, but improved, I think.

Code:
#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;
	
}
 
  • #10
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:
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:
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:
#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.
 
  • Like
Likes 1 person
  • #11
Alright. I'll post my almost-finished product.
 

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

What does the error "expected ']' before ';' token" mean?

This error means that the compiler was expecting to see a closing square bracket "]" before it encountered a semicolon ";". This usually occurs when the syntax of an array declaration or access is incorrect.

How can I fix the "expected ']' before ';' token" error?

To fix this error, you need to check the syntax of your array declaration or access. Make sure that all opening and closing square brackets are in the correct place and that there are no missing or extra brackets. Also, check for any other potential syntax errors in the line of code where the error is occurring.

Why am I getting a "expected ']' before ';' token" error when my code used to work?

This error can occur when you make changes to your code and accidentally introduce a syntax error, such as missing a closing square bracket. It is also possible that the code that used to work was relying on implicit conversions, which may no longer be supported by the compiler you are currently using.

Can a missing semicolon cause an "expected ']' before ';' token" error?

Yes, a missing semicolon can cause this error if it is preventing the compiler from finding the end of a statement. In this case, the compiler may think that the missing semicolon is actually a missing closing square bracket, leading to the error message.

Is the "expected ']' before ';' token" error specific to C++?

Yes, this error is specific to C++ as it is related to the syntax and rules of the language. Other programming languages may have similar error messages for similar types of syntax errors, but the specific wording of this error is unique to C++.

Similar threads

Replies
22
Views
3K
Replies
1
Views
1K
Replies
39
Views
4K
Replies
1
Views
1K
Replies
4
Views
3K
Replies
75
Views
5K
Back
Top