Question on "if" statements...

C

Chris Dollin

William said:
Chris Dollin said:
The OP is have the *language* make the decision for them - C has a
defined "order of precedence" [1].

The compiler is the one that is making the decision as the compiler is the
one that is compiling the code. I'm not saying that the compiler has any
choice in the decision it makes - and I understand the point you are
making. Please recognize that just saying something like "the compiler is
making the decision" is anthropomorphisizing (sp?) to begin with and the
main point is not who (or what) is making the decision but rather that the
OP is NOT making the decision.

The OP is using the language and has decided to write his code thus-and-so.
The rest is a fixed framework.
Really? So something like

if( a || b && c || d )

should present no difficulties and compile the way that it was most likely
meant?

I thought my follow-up covered that. I quote:

| Erm, in my haste I did not make it clear that one should still
| write expressions for clarity - there's a difference between knowing
| the C precedence levels, assuming the reader will know them, and
| writing for the IOCC.

As it happens I agree that &&|| mixes can be confusing - I'd look for
better abstractions, rather than bracketing, to fix them, unless the
constituent expressions were tres short.
 
A

Arthur J. O'Dwyer

OK, this code is compilable, but it requires the miracl
arbitrary-size-number library to run. If you want me to comment out all
the miracl code, I can do that and then repost.

Well, you're going to have to repost anyway, since I don't see any
code attached to your post this time. Since I occasionally see
attachments on my newsfeed, I'm assuming the stripping-of-attachments
is happening somewhere between you and me.
(This is why we --- and everyone else --- tell people not to post
attachments to text-only Usenet groups.)
Should I "inline" the code or "attach" it to this message? If I inline
it, it will definitely not look pretty when it gets through to the other
side. If I attach it, some NG's remove attachments. Please let me know
which way is better.

Posting the code in the message body is better. Your comment about
its "not looking pretty" doesn't make sense --- just think of your
news client's text window (or text-entry area) as a text editor's
window (or text-entry area). Anything that doesn't fit in a 75-character
line needs to be snipped and/or reformatted.
You should never use "hard tabs" on Usenet. (IMHO, you should never
use "hard tabs" in source code, period, especially since the advent of
automatic indenting tools, but *definitely* not on Usenet.)
And of course in c.l.c you shouldn't be using // comments, either
because in C90 they're invalid or because in C99 they're just a royal
PITA to deal with. (Consider the following line of code:

int myident = foo(baz); // Here, we are calling 'foo' to get the
value of sqrt|baz| as an int.

Oh dear, line-wrapping has broken our program!)

Other than these caveats --- which can be handled simply enough by
a mechanical approach --- there's no reason for your code to look ugly.
Unless, of course, it looked ugly to begin with. And then that's your
problem. :)

HTH,
-Arthur

[P.S.: Has anyone ever written a "Usenet code formatter" for C code
that would wrap long lines in the right places, replace // comments
with /* comments */, and detab intelligently? It might find an
audience... ;-) ]
 
D

David Cleaver

Arthur J. O'Dwyer said:
Posting the code in the message body is better. Your comment about
its "not looking pretty" doesn't make sense --- just think of your
news client's text window (or text-entry area) as a text editor's
window (or text-entry area). Anything that doesn't fit in a 75-character
line needs to be snipped and/or reformatted.

Ah, 75 characters, well, here it is in 75 character width glory
(unfortunately, its a bit longer than the 20-60 lines you said earlier, I
wasn't sure what to cut out so I left alot in. This gets called from
another program, so thats why you aren't seeing a main()).
Except for the warnings I've mentioned, it compiles just fine with "gcc -c"

#include <stdio.h>
#include <miracl.h>
#include "arrays.h"

/*=======================================================================*/

void quadSieve(big test_num, big divisor)
{

/* num_primes = 30, its defined in "arrays.h" */
int i_primes[num_primes] = {3,5,7,11,13,17,19,23,29,31,37,41,
43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127};
int b[32] = {0x80000000, 0x40000000, 0x20000000, 0x10000000,
0x8000000, 0x4000000, 0x2000000, 0x1000000,0x800000, 0x400000,
0x200000, 0x100000, 0x80000, 0x40000, 0x20000, 0x10000, 0x8000, 0x4000,
0x2000, 0x1000,
0x800, 0x400, 0x200, 0x100, 0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
int xmodp[num_primes];
int nmodp[num_primes]; /* this holds test_num%p, p a prime */
int **table[num_primes];
int loop_var = 0;
int i = 0;
big x;
big y;
big x_squared;
big x_minus_y;
big x2_minus_n;

/* Now allocate our big vars... */
x = mirvar(0);
y = mirvar(0);
x_squared = mirvar(0);
x_minus_y = mirvar(0);
x2_minus_n = mirvar(0);


/*
**now, create pointers to our 2D arrays...**
"Old Wolf" on comp.lang.c suggested that I create an array of pointers
to my 2-dimensional tables so that I could just make a for loop to
test everything instead of writing it all out in one very large if
statement, so here I am attempting to create an array of pointers to
all of my 2D arrays. Just to give you an idea of the size of each of
these 2D arrays, int table003[3][1], int table005[5][1], ...,
int table037[37][2], and table_k is of size int table_k[k][(k/32)+1],
these are all defined in "arrays.h" And if you want to actually see
one of the defined tables, then here is the beginning of arrays.h:
#ifndef arrays_h_
#define arrays_h_

#define num_primes 30


int table003[3][1] = {{ 0xe0000000},
{ 0x60000000},
{ 0x80000000}};
Following is the part of the code the compiler is having problems with.
The compiler has no problems with the rest of the code.
I guess my only question is how do I create an array pointing to all
of my already declared 2D arrays.
*/
table[0] = &table003;
table[1] = &table005;
table[2] = &table007;
table[3] = &table011;
table[4] = &table013;
table[5] = &table017;
table[6] = &table019;
table[7] = &table023;
table[8] = &table029;
table[9] = &table031;
table[10] = &table037;
table[11] = &table041;
table[12] = &table043;
table[13] = &table047;
table[14] = &table053;
table[15] = &table059;
table[16] = &table061;
table[17] = &table067;
table[18] = &table071;
table[19] = &table073;
table[20] = &table079;
table[21] = &table083;
table[22] = &table089;
table[23] = &table097;
table[24] = &table101;
table[25] = &table103;
table[26] = &table107;
table[27] = &table109;
table[28] = &table113;
table[29] = &table127;

printf("Attempting to factor: ");
outnum(test_num, stdout);
printf("\n");

/*
if test_num is a perfect square, this will catch it...
*/
if (nroot(test_num, 2, x))
{
copy(x, divisor);
return;
}//end if


/*
if we get here, then test_num was not a perfect square and
the floor of the square root of test_num is in x, since we need
the ceil, we will now increment x by one...
*/
incr(x, 1, x);
printf("Initial x: ");
outnum(x, stdout);
printf("\n");

/*
now fill in our two arrays...
*/
for (loop_var = 0; loop_var < num_primes; loop_var++)
{
xmodp[loop_var] = remain(x, i_primes[loop_var]);
nmodp[loop_var] = remain(test_num, i_primes[loop_var]);
}/* end for */

while (1)
{
for (i = 0; i < num_primes; i++)
{
if (table[nmodp][xmodp/32] & b[xmodp%32])
continue;
else
break;
}/* end for */

/*if it passed all of the above tests then it should be = num_primes = 30*/
if (i == num_primes)
{
multiply(x, x, x_squared);
subtract(x_squared, test_num, x2_minus_n);

/*if we get a perfect square, then we are done and we get out of dodge...*/
if (nroot(x2_minus_n, 2, y))
{
subtract(x, y, x_minus_y);
copy(x_minus_y, divisor);

mirkill(x);
mirkill(y);
mirkill(x_squared);
mirkill(x_minus_y);
mirkill(x2_minus_n);

return;
}/*end if*/
}/*end if*/

incr(x, 1, x);
for (loop_var = 0; loop_var < num_primes; loop_var++)
xmodp[loop_var] = (xmodp[loop_var] + 1)%i_primes[loop_var];
}/*end while*/
}/*method quadSieve*/

You should never use "hard tabs" on Usenet. (IMHO, you should never
use "hard tabs" in source code, period, especially since the advent of
automatic indenting tools, but *definitely* not on Usenet.)

OK, I've gotten rid of the hard tabs, and just used two-spaces instead. I
don't have any "automatic indenting tools". I just use notepad to do my
programming.
And of course in c.l.c you shouldn't be using // comments, either
because in C90 they're invalid or because in C99 they're just a royal
PITA to deal with. (Consider the following line of code:

int myident = foo(baz); // Here, we are calling 'foo' to get the
value of sqrt|baz| as an int.

Oh dear, line-wrapping has broken our program!)

OK, I've gotten rid of all of the // type comments and replaced them all
with /* ... */
Other than these caveats --- which can be handled simply enough by
a mechanical approach --- there's no reason for your code to look ugly.
Unless, of course, it looked ugly to begin with. And then that's your
problem. :)

HTH,
-Arthur

I don't think it was all that ugly, its just that sometimes line-wrapping
makes it look bad. I think it actually looked better back when I was using
my // style comments, but since I changed that for this post you won't see
it. Anyway, my current problem is creating an array that points to all of
my already declared 2D arrays. The reason I don't want to make a 3D array
is because that would waste alot of space. I want to try and keep my
tables as small as possible.

Well, please let me know if it is possible in C to create an array that
points to a bunch of other 2-dimensional arrays that are all of differing
sizes. Thanks for your time.

-David C.
 
O

Old Wolf

David Cleaver said:
:

Ok, I just rewrote it and its not compiling. I went with your first
suggestion, since I don't want to do it dynamically. Here's what I've
written:
int *table[num_primes];
table[0] = &table003; //this is line 70 in the program
table[1] = &table005;
table[2] = &table007;
...
And the compiler gives me these "errors":
blah.c: In function 'blah':
blah.c:70: warning: assignment from incompatible pointer type

blah.c:172: subscripted value is neither array nor pointer
here is line 172:
if (table[nmodp][xmodp/32] & b[xmodp%32])

What does that mean? What have I done wrong? I'm not seeing it.


You haven't posted the definitions of table003 etc. but I'm presuming
you have something like:
int table003[10][20] = ...
int table005[30][40] = ...
int table007[25][35] = ...

table[0] is a pointer to int. table003 is an array[10][20] of int.
So you can't point one to the other. The best you can do with your
table[0] is point it to the first int in table003, but this will
not be good enough because you cannot tell from that pointer how to
get to the second row of the table, for example.

Your error message on line 172 is saying that "table"[foo]" cannot
be followed by [bar], which makes sense because table is a pointer
to int, so table[foo] is an actual int.

Since the tables have varying widths, you will have to remember the
width along with a pointer to the first element. Try this:
int *table[] = { table003, table005, ... };
const int table_width[] = { sizeof *table003, sizeof *table005, ... };
and then:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])

This doesn't represent a slow-down, because when you went
table[foo][bar], the compiler silently interprets it as
table[foo * sizeof *table + bar] anyway . There is a small
amount of slowdown in retrieving the table width instead of having
it in the source, but I would expect that if you did some profiling
on the loop version once you're finished, there wouldn't be a noticeable
difference.

Re. other posts on the thread: just because you get something compiling
doesn't mean it's actually going to work, and you were correct that
I wrote "if (cond) break;" but what you actually wanted was
"if (!(cond)) break;", which is exactly equivalent to
"if (cond) continue; else break;", as you pointed out.
 
A

August Derleth

"Arthur J. O'Dwyer" wrote:
[snip about minimal compiling program]
OK, this code is compilable, but it requires the miracl
arbitrary-size-number library to run.

What code? Where? I see no code here.
If you want me to comment out all
the miracl code, I can do that and then repost.

I don't see any big problem about libraries: They rarely impact the
standards-conformance of the code that calls into them. Providing
prototypes for subroutines might be a plus.
Should I "inline" the code or "attach" it to this message? If I inline
it, it will definitely not look pretty when it gets through to the other
side. If I attach it, some NG's remove attachments. Please let me know
which way is better.

Inlining, definitely. Otherwise, there are more than a few people here who
don't get the code at all.
 
D

David Cleaver

Old said:
David Cleaver said:
:

Ok, I just rewrote it and its not compiling. I went with your first
suggestion, since I don't want to do it dynamically. Here's what I've
written:
int *table[num_primes];
table[0] = &table003; //this is line 70 in the program
table[1] = &table005;
table[2] = &table007;
...
And the compiler gives me these "errors":
blah.c: In function 'blah':
blah.c:70: warning: assignment from incompatible pointer type

blah.c:172: subscripted value is neither array nor pointer
here is line 172:
if (table[nmodp][xmodp/32] & b[xmodp%32])

What does that mean? What have I done wrong? I'm not seeing it.


You haven't posted the definitions of table003 etc. but I'm presuming
you have something like:
int table003[10][20] = ...
int table005[30][40] = ...
int table007[25][35] = ...


Yes, this is how I have declared those arrays.
table[0] is a pointer to int. table003 is an array[10][20] of int.
So you can't point one to the other. The best you can do with your
table[0] is point it to the first int in table003, but this will
not be good enough because you cannot tell from that pointer how to
get to the second row of the table, for example.

Your error message on line 172 is saying that "table"[foo]" cannot
be followed by [bar], which makes sense because table is a pointer
to int, so table[foo] is an actual int.

Since the tables have varying widths, you will have to remember the
width along with a pointer to the first element. Try this:
int *table[] = { table003, table005, ... };
const int table_width[] = { sizeof *table003, sizeof *table005, ... };
and then:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])


OK, I've done this, but the compiler is still giving warnings about
initializations from incompatible pointer types. It looks like:
blah.c: In function 'blah':
blah.c:44: warning: initialization from incompatible pointer type
....

Line 44 is where I have:
int *table[] = { table003, table005,...};
I even tried:
int *table[] = { &table003, &table005,...};
But neither of the above made it past the compiler without the compiler
giving warnings. The code actually does compile, but I'm not sure I'd
trust it to run correctly. Any thoughts on how to get around this? Or is
this valid C and I'm just stuck with a sub-par compiler?
This doesn't represent a slow-down, because when you went
table[foo][bar], the compiler silently interprets it as
table[foo * sizeof *table + bar] anyway . There is a small
amount of slowdown in retrieving the table width instead of having
it in the source, but I would expect that if you did some profiling
on the loop version once you're finished, there wouldn't be a noticeable
difference.

Re. other posts on the thread: just because you get something compiling
doesn't mean it's actually going to work, and you were correct that
I wrote "if (cond) break;" but what you actually wanted was
"if (!(cond)) break;", which is exactly equivalent to
"if (cond) continue; else break;", as you pointed out.


Thanks again for your help so far.

-David C.
 
O

Old Wolf

David Cleaver said:
Old said:
Since the tables have varying widths, you will have to remember the
width along with a pointer to the first element. Try this:
int *table[] = { table003, table005, ... };
const int table_width[] = { sizeof *table003, sizeof *table005, ... };
and then:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])


OK, I've done this, but the compiler is still giving warnings about
initializations from incompatible pointer types. It looks like:
blah.c: In function 'blah':
blah.c:44: warning: initialization from incompatible pointer type


My mistake - the address of the first int in the table is &table003[0][0]
etc., which can be written more compactly as *table003, so you can go:
int *table[] = { *table003, *table005, *table007 }; etc.
 
D

David Cleaver

Old said:
David Cleaver said:
Old said:
Since the tables have varying widths, you will have to remember the
width along with a pointer to the first element. Try this:
int *table[] = { table003, table005, ... };
const int table_width[] = { sizeof *table003, sizeof *table005, ... };
and then:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])


OK, I've done this, but the compiler is still giving warnings about
initializations from incompatible pointer types. It looks like:
blah.c: In function 'blah':
blah.c:44: warning: initialization from incompatible pointer type


My mistake - the address of the first int in the table is &table003[0][0]
etc., which can be written more compactly as *table003, so you can go:
int *table[] = { *table003, *table005, *table007 }; etc.


Exellent! It works perfectly now! Thank you very much! Actually, I also
found out one thing, when working with the table_width, the "sizeof
*table003" returned the size of the variable in bytes, and not in ints.
So, I had to go back through and divide it by (sizeof(int)) to get the
array access at:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])
to work properly.

I do have one more question if you don't mind. I would like to write the
above array declarations more succinctly. Instead of writing:
const int table_width[] = { sizeof *table003, sizeof *table005,...
for 30 (or more) different tables, I would like to write:

int table_width[num_primes];
for (i = 0; i < num_primes; i++)
table_width[num_primes] = (sizeof *table)/(sizeof(int));

However, when I run this code all that is in table_width is a bunch of
ones. For the first 10 tables thats ok, but the rest are larger than "1".
There are some 2's, 3's, and a couple of 4's also. Can you tell me if
there is a way I can do this, since apparently the code I tried to write
isn't quite cutting it. Thanks again for all your help so far.

-David C.
 
A

Arthur J. O'Dwyer

Old said:
David Cleaver said:
Old Wolf wrote:
Since the tables have varying widths, you will have to remember the
width along with a pointer to the first element. Try this:
int *table[] = { table003, table005, ... };
const int table_width[] = {sizeof *table003, sizeof *table005, ...

My mistake - the address of the first int in the table is &table003[0][0]
etc., which can be written more compactly as *table003, so you can go:
int *table[] = { *table003, *table005, *table007 }; etc.

Exellent! It works perfectly now! Thank you very much! Actually, I also
found out one thing, when working with the table_width, the "sizeof
*table003" returned the size of the variable in bytes, and not in ints.

Correct --- the 'sizeof' operator *always* deals in bytes.
So, I had to go back through and divide it by (sizeof(int)) to get the
array access at:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])
to work properly.


One common C idiom you should know is

#define NELEM(arr) (sizeof arr / sizeof *arr)

This macro, given an array object as the 'arr' parameter, will tell
you the number of elements in that array. (It will NOT work on
pointers, for obvious reasons!)
I do have one more question if you don't mind. I would like to write the
above array declarations more succinctly. Instead of writing:
const int table_width[] = { sizeof *table003, sizeof *table005,...
for 30 (or more) different tables, I would like to write:

int table_width[num_primes];
for (i = 0; i < num_primes; i++)
table_width[num_primes] = (sizeof *table)/(sizeof(int));

However, when I run this code all that is in table_width is a bunch of
ones.


Well, naturally. Let's evaluate that code above:

for (i = 0; i < num_primes; i++)
table_width[num_primes] =

What have I told you about hard TABs in posted code?...
Secondly, we see that you're assigning something to a non-existent
object 'num_primes' times. Redundant *and* wrong --- that's never
a good sign.

(sizeof *table)

This evaluates to the size of *table in bytes. Since *table
is an 'int', this is the same as 'sizeof (int)'.

/(sizeof(int));

This is *also* 'sizeof(int)', so of course the result is 1.
Assign to the non-existent 'table_width[num_primes]', rinse,
and repeat.

The only correct solution is the solution Old Wolf already
gave you:

int table_width[] = { NELEM(table003), NELEM(table005), ... };

Of course there are preprocessor tricks to save you a lot of
typing, but why bother? If you find yourself unable to hammer
in the screw with this tool, just try a different one. For
example:

int table003[] = { ...., -1 };
int table005[] = { ........, -1 };
int table007[] = { ......, -1 };

int find_size(int *tab)
{
int i;
for (i=0; tab != -1; ++i)
continue;
return i;
}

Or perhaps just try an algorithm that doesn't require a load of
variously-sized arrays to work. What were you trying to do, again
--- was it primality testing? I'm sure there exist better algorithms
than this one. Bunches of tables always make me suspicious.

-Arthur
 
C

CBFalconer

David said:
David Cleaver wrote:

if (table001[n[0]][x[0]>>5]&b[x[0]&0x1f] != 0 &&
table002[n[1]][x[1]>>5]&b[x[1]&0x1f] != 0 &&
table003[n[2]][x[2]>>5]&b[x[2]&0x1f] != 0 &&
... &&
table030[n[29]][x[29]>>5]&b[x[29]&0x1f] != 0)
{
.... snip ...

Thank you very much. I never thought about there being a precedence
issue. I've fixed my code to better reflect what I was doing. [And
I was wanting (x & y), not x & (y != 0), I've changed it all to be
of the form (x & y) && ...]

May I ask, without making those tables 3-dimensional, how could I
make that code segment look better? Someone earlier in this thread
mentioned putting it into a for loop, but I can't see how that'd be
possible with 30 different tables.

There is no such thing as a 2d or 3d array in C; they are all one
dimensional. The 2d/3d effects can be simulated by changing what
the array component consists of.

So let us assume that you have your existing table001, table002,
etc. set up and functional. You can now create an array of
pointers to these tables, say:

int *tables[] = {&table000, &table001, &table002, &table003,
&table004, &table005, ....
&table028, &table029};

#define TABLEMAX = (sizeof(tables) / sizeof(table[0]))

Now you can evaluate the equivalent of your expression above, with
corrected precedence, with a routine such as:

int querytbls(int *tables)
{
int i;
for (i = 1; i < TABLEMAX; i++) {
if (0 == *(tables)[n[x >> 5] & b[x & 0x1f])
return 0;
}
return 1;
} /* untested */

Now all you have to do to modify it is create the appropriate
tables and add them to the declaration of tables above. The point
is that the machine and the compiler are much better at this sort
of bum work than you or I are.
 
R

RoSsIaCrIiLoIA

David said:
David Cleaver wrote:

if (table001[n[0]][x[0]>>5]&b[x[0]&0x1f] != 0 &&
table002[n[1]][x[1]>>5]&b[x[1]&0x1f] != 0 &&
table003[n[2]][x[2]>>5]&b[x[2]&0x1f] != 0 &&
... &&
table030[n[29]][x[29]>>5]&b[x[29]&0x1f] != 0)
{
... snip ...
int *tables[] = {&table000, &table001, &table002, &table003,
&table004, &table005, ....
&table028, &table029};

#define TABLEMAX = (sizeof(tables) / sizeof(table[0]))

Now you can evaluate the equivalent of your expression above, with
corrected precedence, with a routine such as:

int querytbls(int *tables)
{
int i;
for (i = 1; i < TABLEMAX; i++) {
if (0 == *(tables)[n[x >> 5] & b[x & 0x1f])


in the above seems to me you have forget ']'
if it is v
if (0 == *(tables)[n][x >> 5] & b[x & 0x1f])
you know that it is evaluated like
if( (0==*(tables)[n][x>>5]) & b[x & 0x1f] )

I would write
"if( (tables[n][x>>5] & b[x & 0x1f] )==0 )"

CBFalconer it\she\they-- Ros 0, 2
 
R

RoSsIaCrIiLoIA

David said:
David Cleaver wrote:

if (table001[n[0]][x[0]>>5]&b[x[0]&0x1f] != 0 &&
table002[n[1]][x[1]>>5]&b[x[1]&0x1f] != 0 &&
table003[n[2]][x[2]>>5]&b[x[2]&0x1f] != 0 &&
... &&
table030[n[29]][x[29]>>5]&b[x[29]&0x1f] != 0)
{
... snip ...

Thank you very much. I never thought about there being a precedence
issue. I've fixed my code to better reflect what I was doing. [And
I was wanting (x & y), not x & (y != 0), I've changed it all to be
of the form (x & y) && ...]

May I ask, without making those tables 3-dimensional, how could I
make that code segment look better? Someone earlier in this thread
mentioned putting it into a for loop, but I can't see how that'd be
possible with 30 different tables.

There is no such thing as a 2d or 3d array in C; they are all one
dimensional. The 2d/3d effects can be simulated by changing what
the array component consists of.

So let us assume that you have your existing table001, table002,
etc. set up and functional. You can now create an array of
pointers to these tables, say:

int *tables[] = {&table000, &table001, &table002, &table003,
&table004, &table005, ....
&table028, &table029};

#define TABLEMAX = (sizeof(tables) / sizeof(table[0]))

Now you can evaluate the equivalent of your expression above, with
corrected precedence, with a routine such as:

int querytbls(int *tables)
here int **tables
1 error
{
int i;
for (i = 1; i < TABLEMAX; i++) {
if (0 == *(tables)[n[x >> 5] & b[x & 0x1f])

here
if ( ( *(tables)[n][x >> 5] & b[x & 0x1f] ) == 0)
1+1 errors
=3
 
D

David Cleaver

Arthur J. O'Dwyer said:
Old said:
David Cleaver wrote:
Old Wolf wrote:
Since the tables have varying widths, you will have to remember the
width along with a pointer to the first element. Try this:
int *table[] = { table003, table005, ... };
const int table_width[] = {sizeof *table003, sizeof *table005, ...

My mistake - the address of the first int in the table is &table003[0][0]
etc., which can be written more compactly as *table003, so you can go:
int *table[] = { *table003, *table005, *table007 }; etc.

Exellent! It works perfectly now! Thank you very much! Actually, I also
found out one thing, when working with the table_width, the "sizeof
*table003" returned the size of the variable in bytes, and not in ints.

Correct --- the 'sizeof' operator *always* deals in bytes.
So, I had to go back through and divide it by (sizeof(int)) to get the
array access at:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])
to work properly.


One common C idiom you should know is

#define NELEM(arr) (sizeof arr / sizeof *arr)

This macro, given an array object as the 'arr' parameter, will tell
you the number of elements in that array. (It will NOT work on
pointers, for obvious reasons!)


Why won't it work on what the pointers are pointing to?

int *table[] = { table003, table005, ... };
int table_width[] = {sizeof *table003, sizeof *table005, ... };

table holds a pointer to table003, table005, ... right?


So, instead of doing the above, why can't I use:

int *table[] = { table003, table005, ... };
for (i = 0; i < num_primes; i++)
table_width = sizeof **table;

Is C incapable of doing this? Is the information lost when we create our
array of pointers? I'm just curious why this won't work. Thanks for any
insights you (or anyone else) can provide.

-David C.
 
C

Chris Torek

Why won't [the sizeof sequence, "sizeof array / sizeof array[0]" for
instance] work on what the pointers are pointing to?

Because pointers lose information. The extra information attached
to an array object (besides its name, static-ness, etc.) is a *pair*
of things:

number-of-elements = N, element-type = T

(where N is an integer constant in C89, or the special value "unknown";
C99 adds a new wrinkle with Variable Length Arrays). The information
attached to a pointer object is just one item:

pointer-target-type = T

and The Rule that transforms an array object into a pointer value
discards the number-of-elements portion.

The sizeof operator is one of the few operators that does *not*
transform an array object into a pointer value. By suppressing
this transformation, it avoids losing the size information.
... Is the information lost when we create our array of pointers?

Yes.

There is another approach you can use -- instead of carrying the
sizes around in an auxiliary array, you can carry the locations
around in an auxiliary array.

To recap: you have (at the moment) a collection of one-dimensional
arrays whose elements are in turn one-dimensional arrays (of int,
I think). That is, you have an object like "table003" whose type
is "array N1 of (array N2 of int)", then one like table005, and
one like table013, and so on. Unfortunately, the element-types --
"array N2 of int" for table003 for instance -- change, because the
constant (N2) is different for table003 than for table041, whose
constant is different from that for table097, and so on.

The trick, as always, is to draw a picture, something like the
one that can be found at <http://web.torek.net/torek/c/pa.html>.
In this case, however, the picture is much more complicated. We
have:

table003:
-----
| . |
-----
| . |
-----
| . |
-----
...
table041:
-------------
| . | . | . |
-------------
| . | . | . |
-------------
| . | . | . |
-------------

Because pointers must encode the size of the element to which
they point, a pointer to a "row" of table041 has to point to
a three-long-row (in the example above), while a pointer to a
"row" of table003 has to point to a one-long row (in the example
above). Thus, you cannot use a single pointer type to point to
both "rows of table003" and "rows of table041".

The trick discussed earlier is to point not to *rows* of each table,
but to the *very first int* in each table -- the box at (0,0).
Since C requires that array memory be "locally flat", and C compilers
that check for exceeding array subscript bounds are so rare that
few have ever even heard of one, we can then "cheat". Adding 1 to
a pointer pointing to table041[0][0] gets you to table041[0][1];
adding 1 again gets you to table041[0][2]; and adding 1 more is
*technically* undefined -- there is no table041[0][3] -- but on
all "real world" implementations it just wraps around to get to to
table041[1][0]. In table003, the wrap-around occurs right away,
because there is a table003[0][0] but no table003[0][1].

Instead of using this undefined behavior to achieve the desired
effect, though, you can throw more memory at the problem. (This
may actually slow it down.) Take the above drawing, with table003
and table041 as they are, and add some auxiliary tables:

aux_ptrs_for_003: table003:
------------- -----
| * | * | *-|-----> | . |
--|---|------ -----
| +-----------> | . |
| -----
+---------------> | . |
-----
...
aux_ptrs_for_041: table041:
------------- -------------
| * | * | *-|-----> | . | . | . |
--|---|------ -------------
| +-----------> | . | . | . |
| -------------
+---------------> | . | . | . |
-------------

Now each "aux_ptrs_for_nnn" array has type "array N of pointer to
int". (In the example above, N is always 3, but in practice it
will -- presumably -- vary. This will not matter because we are
about to eliminate the constant N, through that very same thing
that causes heartache with "sizeof".) Each "aux" array has its
various elements pointing to the [0][0], [1][0], and [2][0] element
of the corresponding "table". Just for illustration I will make
table003 only have two rows here:

int table003[2][1] = { ... };
int table041[3][3] = { ... };

int *aux_003[2] = { &table003[0][0], &table003[1][0] };
int *aux_041[3] = { &table041[0][0], &table041[1][0], &table041[2][0] };

Now we just need one last table, the "table of pointers that
points to the first of each aux pointer". For illustration
I will add aux_005 and aux_007 (not shown above):

#define N1 4 /* table[0] through table[3] */
int **table[N1] = { &aux_003[0], &aux_005[0], &aux_007[0], &aux_041[0] };

The picture here looks like this:

table: aux_007:
----------------- -------------
| * | * | * | * | +-> | * | * | * | (pointer arrows not shown)
--|---|---|---|-- | -------------
. | | | |
. | +---|----------+
. . |
v . | aux_042:
(aux_003). | -------------
v +--> | * | * | * |
(aux_005) -------------

Note that all of the "aux" arrays may be scattered around anywhere
in memory; all we demand is that there be a set of pointers to them,
all in a neat row, in the thing called "table". Each pointer --
each element of the table named "table" -- has type "pointer to
(pointer to int)", so that it points to the first of some unspecified
number of pointers. Each of those pointers has type "pointer to
int", so that it points to the first of some unspecified number
of "int"s.

If you look in table[0], you get the arrow pointing to aux_003[0].
If you follow that arrow -- as is the case for normal uses of the
value, including further subscripting -- you get the first element
of the array "aux_003", which is another pointer -- another arrow.
You can subscript by however many elements there really are in the
aux_003 array, to get the j'th pointer: table[0][j] is the j'th
pointer in the aux_003 array. Follow *that* arrow and you point
to table003[j][0], because we made aux_003[j] point to table003[j][0]
when we created the aux_003 array.

Thus, table[j][k] is the i'th "aux" array, then its "j'th" element
(which points to the j'th row of a tableNNN), then that row's k'th
element.

Note that the table named "table" itself, and table, and
table[j], can all be dynamically allocated (by replacing the
array "table", of size N1, with a pointer to the same element type
that the table array had), if you prefer:

int ***table;

table = malloc(N1 * sizeof *table);
if (table == NULL) ...
/* now table, 0 <= i < N1, is valid */

table = malloc(N2 * sizeof *table);
if (table == NULL) ...
/* now table[j], 0 <= j <= N2; is valid */

table[j] = malloc(N3 * siezof *table[j]);
if (table[j] == NULL) ...
/* now table[j][k], 0 <= k < N3, is valid */

As before, there is no reason that N2 has to be the same for every
value of i, nor that N3 has to be the same for every pair (i,j).
If you draw a picture of this situation, it will look almost the
same as the one where "table" has type "int **[4]", except that
the four "int **" elements are now floating off in space somewhere
and "table" is just a pointer pointing to the first one, and the
"aux" name are gone -- they too are just floating off in space,
allocated by malloc:

table:
-----
| *-|--+
----- |
|
+-------------+
|
| ----------------- -------------
+->| * | * | * | * | +-> | * | * | * | (pointer arrows not shown)
--|---|---|---|-- | -------------
. | | | |
. | +---|----------+
. . |
v . |
. | -------------
v +--> | * | * | * |
-------------
 
O

Old Wolf

[we ended up with the following code: ]
int *table[] = { *table003, *table005, *table007 }; etc.
const int table_width[] = { sizeof *table003, sizeof *table005, ... };
and refer to each int as:
table[ nmodp * table_width + xmodp/32 ]
Exellent! It works perfectly now! Thank you very much! Actually, I also
found out one thing, when working with the table_width, the "sizeof
*table003" returned the size of the variable in bytes, and not in ints.
So, I had to go back through and divide it by (sizeof(int)) to get the
array access at:
if (table[ nmodp * table_width + xmodp/32 ] & b[xmodp%32])
to work properly.
Right.

I do have one more question if you don't mind. I would like to write the
above array declarations more succinctly.


You could go:
const int table_width[] = { dimof(*table003), dimof(*table005), ... };
with
#define dimof(x) (sizeof(x) / sizeof((x)[0]))
(or call this macro something that makes sense to you)

which gives you the number of items in each array (divide the size
in bytes, by the size of each item). In this case, the sizeof **table003
is sizeof(int). This is probably best, as all the maths is done at
compile time.
Instead of writing:
const int table_width[] = { sizeof *table003, sizeof *table005,...
for 30 (or more) different tables, I would like to write:

int table_width[num_primes];
for (i = 0; i < num_primes; i++)
table_width[num_primes] = (sizeof *table)/(sizeof(int));


table is a pointer to int. (NOT a pointer to array)
*table is an int.
sizeof(*table) is therefore the same as sizeof(int).

You can't have an array of pointers to arrays of different widths,
which is why we settled for the solution of having an array of
pointers to int.

Just adding the "/sizeof(int)" into the table[blah] is
also an option.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

Lexical Analysis on C++ 1
For loop with if statement 3
Need an if statement 8
First time question 1
Minimum Total Difficulty 0
It doesn't see my 'if' statements 7
Pythen question 0
Function is not worked in C 2

Members online

Forum statistics

Threads
473,774
Messages
2,569,598
Members
45,152
Latest member
LorettaGur
Top