Specific pointers to elements of a data structure

My program works just fine, but I have to admit I forgot a few things that would make some aspects of this less redundant. Note I am aware of its C/C++ hybrid nature and lack of error handling. This was just a quick whip-up.

Given this struct:
1
2
3
4
5
struct Triplet {
	short blu;
	short grn;
	short red;
} triplet, quantiPal[256];


And declarations:
1
2
3
4
5
6
7
8
FILE *srcFile;
FILE *outFile;
char *pixelData;
int palPos = 0;
char byte[1] = {NULL};
char b[1] = {NULL};
char g[1] = {NULL};
char r[1] = {NULL};


And some snippets:
1
2
3
4
5
6
7
8
9
10
11
12
13
int j;
for(j = 0; j <= palPos; j++){
	if(compTriplet(triplet, quantiPal[j]) == 0) {
		byte[0] = j;
		fwrite(byte, 1, 1, outFile);
		break;
	}
	if(j == palPos) {
		quantiPal[j] = triplet;
		palPos++;
		break;
	}
}

...
1
2
3
4
5
6
7
8
9
for(i = 0; i <= 255; i++){
	b[0] = quantiPal[i].blu;
	g[0] = quantiPal[i].grn;
	r[0] = quantiPal[i].red;

	fwrite(b, 1, 1, outFile);
	fwrite(g, 1, 1, outFile);
	fwrite(r, 1, 1, outFile);
}


The char variables byte, b, g, and r are redundant, but a quick fix to the const void pointer type requirement of the first parameter in fwrite and fread. I understand a simple type cast of char* won't work here. Could someone jog my memory of how I get that struct (and its elements) to behave like I want?
Last edited on
What does the struct quantiPal look like?
The struct I had previously was irrelevant.

Thanks for catching that. It is now fixed above as Triplet.
Last edited on
Your Triplet has all shorts but you assign those shorts to chars. Didn't the compiler say something about that?
This compiles
 
fwrite((char *)&quantiPal[i],sizeof(Triplet),1,outFile); 

But do you or don't you want the 3 8-bit values or 3 16-bit values

Last edited on
Use of pointer char type-cast results in runtime errors, specifically access violations. I've isolated these hiccups to these changes as it runs fine (and correctly) in its previous form.

I need just a single byte. The program takes a char and works with its ascii value. An algorithm spits out a value that needs to be encoded back into a char.

Thanks for looking into it. Look forward to your other thoughts.
Since you just want a single byte you don't want to use quantiPal because it is a short. But using the type cast shouldn't cause a access violation. And you put the (char *)&quantiPal[i]?
I took note of the &, but didn't apply it in my haste. This corrected everything and makes perfect sense. Thanks for the advice.

I'm not quite sure what you are getting at with your first statement. Mind to clarify for my dense skull? I need to operate on it as a numerical value, only using short as most other structs I use deal with tons of data. Integers would work just as well and are probably faster anyways. But I'm gathering I'm missing something here (again). Thanks.
Last edited on
Before with
1
2
3
fwrite(b, 1, 1, outFile);
fwrite(g, 1, 1, outFile);
fwrite(r, 1, 1, outFile);

you were writing 3 one byte (chars) values and now with
 
fwrite((char *)&quantiPal[i],sizeof(Triplet),1,outFile); 

you are writing 3 two byte (shorts) values.
I just wanted to make that clear to make sure that is what you wanted for the program output. Your original question was about the pointers and I think that is OK but is the solution to your question the correct answer for your program?
No, you are right to question that. I need 3 single byte chars.

What does this typecast do to the elements blu, grn, and red?:
1
2
3
fwrite((char*)&quantiPal[i].blu, sizeof(Triplet), 1, outFile);
fwrite((char*)&quantiPal[i].grn, sizeof(Triplet), 1, outFile);
fwrite((char*)&quantiPal[i].red, sizeof(Triplet), 1, outFile);


Something I just realized and embarrassed to even ask: can you do arithmetic on a single char? If that is the case, I have no reason to convert them into anything.

For 3 single byte chars use
1
2
3
fwrite((char*)&quantiPal[i].blu, 1, 1, outFile);
fwrite((char*)&quantiPal[i].grn, 1, 1, outFile);
fwrite((char*)&quantiPal[i].red, 1, 1, outFile);

Q: Can you do arithmetic on a single char?
A: Yes.
1
2
3
4
5
6
7
8
9
10
#include <cstdlib>
#include <cstdio>
using namespace std;
int main()
{ 
  char b(1),c(2);
  b += c;
  printf("b: %d\n",b);
  return 0;
}

Output:
b: 3
Last edited on
fwrite( (char*) quantiPal, sizeof(quantiPal), 1, outFile ); That will write all the array.
Yes, I had originally provided 1 for the size as an argument in fwrite and wondered why you suggested a sizeof(Triplet), though I now understand your intent at that time.

I hate that I missed this simple aspect of chars, as in other languages sometimes the closest thing you could get to a char was a single index string which could not be used for arithmetic.

Thanks again.

EDIT: Just caught your post ne555. Another slash at redundancy! Thanks!
Last edited on
Sorry for the double post, but as an additional follow-up to ne555's tip, are there any problems doing this rather than just passing individual elements? Aren't structures limited to organization of data and might resort to byte padding on some compilers?
Yes, if you had
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

using std::cout;
using std::endl;

struct tt {
   int a;
   short b;
   int c;
};

int main()
{
  cout << "Sizeof(tt):  " << sizeof(tt) << endl;
  return 0;
}

Output
Sizeof(tt):  12

This would cause you to to have too much data in the output file. You would have to be careful that what you code is what you want.
There a way to organize data (think struct) any other way that is reliable in passing 'raw' data structures?

I understand there is a performance issue with this and that it is even platform dependent, but given huge amounts of elements in a struct, it would be quite useful to not have to feed in one element at a time.
Last edited on
Si, one should organize the data in your struct correctly or use #pragma pack.
Quick thought: even with correct organization of data, how do you avoid it? Your example should spit out 10 bytes, but clearly an extra 2 were used for alignment. And another issue is that in some cases that short could be something other than 16 bits.... This thread has completely gone off-topic (my fault) and with your response I will leave it be.

If you use a #pragma pack(1) it will anlign the struct on a byte boundary.
http://publib.boulder.ibm.com/infocenter/compbgpl/v9v111/index.jsp?topic=/com.ibm.xlcpp9.bg.doc/compiler_ref/pragma_pack.htm
Note you would pay a performance penalty.

You are correct about the 16-bit short, that could happen. But if you used stdint.h and used int16_t that problem might be avoided.
No worries.
Last edited on
Topic archived. No new replies allowed.