Problem with pointers, VS says int is null?

matorin57 (14)
I am writing a sale compiler for a garage sale my debate team is managing, this is the secondary compiler to the main class and it is giving me a runtime error. The visual studio code anyalsis says

1
2
3
4
5
6
7
8
C6385	Read overrun	Reading invalid data from 'files[l].list':  the readable size is '((unsigned int)=len*1)*80+4' bytes, but '160' bytes may be read.	Sales Compiler	salecompiler.cpp	23
'l' is NULL			17
Enter this loop, (assume 'l<len')			17
'l' is an Output from 'std::basic_string<char,std::char_traits<char>,std::allocator<char> >::=' (declared at c:\program files (x86)\microsoft visual studio 11.0\vc\include\xstring:969)			19
Enter this loop, (assume 'i<temp[l].length')			21
'i' may equal 1			21
Continue this loop, (assume 'i<temp[l].length')			21
Invalid read from 'files[l].list[1]', (readable range is 0 to 0)			23


Here is the code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SaleCompiler::SaleCompiler(SaleList * temp, int len )
{
	final = NULL;
	files = new SaleList[len];
	int l = 0;
	for(l = 0;l<len;l++)
	{
		files[l].fileName = temp[l].fileName;
		files->list = new Sale[len];
		for(int i = 0;i<temp[l].length;i++)
		{
			files[l].list[i].setHour(temp[l].list[i].getHour());
			files[l].list[i].setMin(temp[l].list[i].getMin());
			files[l].list[i].setSec(temp[l].list[i].getSec());
			files[l].list[i].setName(temp[l].list[i].getName());
			files[l].list[i].setTime(temp[l].list[i].getTime());
			files[l].list[i].setPrice(temp[l].list[i].getPrice());
		}
		files[l].length = temp[l].length;
	}
	length = len;
}


Dwibble (10)
Objects with pointers use the -> operator to access public methods instead of the . operator. So, any time you need to access the temp variable, you'll have to use it like this:

1
2
3
files[l].fileName = temp[l]->fileName;
//...
files[l].length = temp[l]->length;


You also might want to make sure that the files variable is a pointer-type too, otherwise, you can't allocate space on the heap for a new SaleList object.

1
2
3
// Lines 3 and 4
int final = NULL;
SaleList* final = new SaleList[len];


Hope this helps.
Last edited on
matorin57 (14)
I changed it to
1
2
3
4
5
6
7
8
9
10
11
12
files[l].fileName = temp[l]->fileName;
		files->list = new Sale[len];
		for(int i = 0;i<temp[l];i<length;i++)
		{
			files[l].list[i].setHour(temp[l].list[i].getHour());
			files[l].list[i].setMin(temp[l].list[i].getMin());
			files[l].list[i].setSec(temp[l].list[i].getSec());
			files[l].list[i].setName(temp[l].list[i].getName());
			files[l].list[i].setTime(temp[l].list[i].getTime());
			files[l].list[i].setPrice(temp[l].list[i].getPrice());
		}
		files[l-1].length = temp[l-1]->length;

but it wont compile it says that expression(temp[l]->fileName;temp[l]->length)
must have a pointer type.
Files is a pointer
SaleList * files;

Sale*final;
here is the header file if it will help
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
#include "Sale.h"
#include "SaleList.h"
class SaleCompiler
{
public:
	SaleCompiler(void);
	SaleCompiler::SaleCompiler(SaleList * temp, int len);
	~SaleCompiler(void);
	void getFinal(Sale *temp);
	void sortFinal();
	void mergeFiles();
	int getTotalSize()
	{
		return totalSize;
	}
protected:
	SaleList * files;
	Sale * final;
	int totalSize;
	int length;
};
Last edited on
Disch (8337)
You are stepping out of bounds of your array and accessing array elements that don't exist.

This block of code has several problems. Note my comments:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
SaleCompiler::SaleCompiler(SaleList * temp, int len )
{
	final = NULL;
	files = new SaleList[len];  // allocating 'len' elements for 'files'.  This is good.
	int l = 0;
	for(l = 0;l<len;l++)  // using 'l' to index 'files'.  As long as 'l' is less than 'len', this is good.
	{
		files[l].fileName = temp[l].fileName;
		files->list = new Sale[len];  // PROBLEM: you are doing files->list which is the same as files[0].list, which probably isn't what you wanted.
		// also you are allocating 'len' elements and not 'temp[l].length' elements like you probably wanted
		for(int i = 0;i<temp[l].length;i++)
		{
			files[l].list[i].setHour(temp[l].list[i].getHour()); // PROBLEM surfaces again here.  You are using 'l' to index temp and files, which is fine, but you are using 'i' to index list, which is wrong.
// what if 'i' is greater than len?  If that happens: EXPLODE
//  also, because you never set files[l].list to anything, it's probably a bad pointer (see files->list problem above) 



Another problem is you are doing all these new[]s but never any delete[]s, which means you are leaking memory. Every new[] must have a matching delete[].

The easiest way to manage that is to simply don't use new if you can avoid it.

Here, you could do this with a vector instead.

Futhermore... if you're using vectors, you don't have to worry about managing memory or even copying objects like this. You can just copy the vectors in full.

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#pragma once
#include "Sale.h"
#include "SaleList.h"
#include <vector>  // use vectors!
class SaleCompiler
{
public:
	SaleCompiler(); // <- not important... but get rid of that (void) business.  That's C garbage.
	SaleCompiler::SaleCompiler(const std::vector<SaleList>& temp); // <-take a vector instead of a pointer+length
	~SaleCompiler();  // <- getting rid of (void) garbage here too
	void getFinal(Sale *temp);
	void sortFinal();
	void mergeFiles();
	int getTotalSize()
	{
		return totalSize;  // <- I'm not sure what to change this to.  Either files.size() or final.size(), whichever size you intended here
	}
protected:
/*	SaleList * files;  get rid of all this crap
	Sale * final;
	int totalSize;
	int length;
*/
	// replace it with vectors:
	std::vector<SaleList> files;
	std::vector<Sale> final;
};


/*

Now your big complicated constructor:

SaleCompiler::SaleCompiler(SaleList * temp, int len )
{
	final = NULL;
	files = new SaleList[len];
	int l = 0;
	for(l = 0;l<len;l++)
	{
		files[l].fileName = temp[l].fileName;
		files->list = new Sale[len];
		for(int i = 0;i<temp[l].length;i++)
		{
			files[l].list[i].setHour(temp[l].list[i].getHour());
			files[l].list[i].setMin(temp[l].list[i].getMin());
			files[l].list[i].setSec(temp[l].list[i].getSec());
			files[l].list[i].setName(temp[l].list[i].getName());
			files[l].list[i].setTime(temp[l].list[i].getTime());
			files[l].list[i].setPrice(temp[l].list[i].getPrice());
		}
		files[l].length = temp[l].length;
	}
	length = len;
}

... can be greatly simplified:

*/

SaleCompiler::SaleCompiler(const std::vector<SaleList>& temp )
    : files(temp)  // done!
{
    // files = temp;  // <- this would have the same effect, more or less, and would also work
    //   but is less optimal that using files' constructor as illustrated above.
}




EDIT:

In case you are unfamiliar with vectors, they're basically resizable arrays:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vector<int> foo(10);  // an array of 10 ints

// can treat it just like an array:
foo[0] = 5;
foo[1] = foo[0] + 2;

// but you can also resize it:
foo.resize(50);  // now it has 50 ints instead of just 10.

// and you can also append things to the end easily:
foo.push_back(5);  // pushes '5' onto the end of the array.  Array now has 51 elements.

// and they're also copyable:
vector<int> bar;  // another array

bar = foo;  // now the 'bar' array is a copy of the 'foo' array. 
Last edited on
matorin57 (14)
Thank you so much Disch, I was compeletely stumped. I should really read into vectors considering you just simplified my constructor to one line
Registered users can post here. Sign in or register to post.