Discussion:
What am I doing wrong here?
(too old to reply)
DFS
2017-05-13 04:39:01 UTC
Permalink
Just trying to get some random chars and ints:

---------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int main(int argc, char *argv[])
{

int i;
char *randName;
int randRate;
char *randJob;

char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};

int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);

for(i=0;i<atoi(argv[1]);i++)
{
srand(time(NULL));
sprintf(randName ,"%s", names[rand()%namescount]);
srand(time(NULL));
sprintf(randRate ,"%d", rates[rand()%ratescount]);
srand(time(NULL));
sprintf(randJob ,"%s", jobs [rand()%jobscount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
}

return 0;
}
---------------------------------------------------------


This line near the end:
sprintf(randRate ,"%d", rates[rand()%ratescount]);

throws "warning: assignment makes pointer from integer without a cast"

It compiles, but errors out on that line when I run it.


Thanks
DFS
2017-05-13 05:03:01 UTC
Permalink
Post by DFS
for(i=0;i<atoi(argv[1]);i++)
{
srand(time(NULL));
sprintf(randName ,"%s", names[rand()%namescount]);
srand(time(NULL));
sprintf(randRate ,"%d", rates[rand()%ratescount]);
srand(time(NULL));
sprintf(randJob ,"%s", jobs [rand()%jobscount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
}
Edit: not causing the warning, but I found out the rand seed needs to
happen once, outside the for loop.
Jens Thoms Toerring
2017-05-13 06:55:09 UTC
Permalink
Post by DFS
---------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i;
char *randName;
int randRate;
char *randJob;
char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};
int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);
for(i=0;i<atoi(argv[1]);i++)
{
srand(time(NULL));
sprintf(randName ,"%s", names[rand()%namescount]);
Already this line is broken like all the others where you
use sprintf(). sprintf() tries to put a string into the
memory pointed to by the first argument. For that to work
the first argument must be a (pointer to a) char array
large enough to hold the complete string sprintf() will
try to put into it. But what you pass it here is an un-
initilaozed pointer, thus pointing to some random place
in memory. If you're lucky that will crash your program
on the first attempt with a segmentation fault, but if you
are unlucky it will seem to work but will corrupt the
memory of your program with unpredictable consequences.
Post by DFS
srand(time(NULL));
sprintf(randRate ,"%d", rates[rand()%ratescount]);
Now here you don't even pass the required pointer to a
char array but an int as the first argument. That's what
the compiler notices and complains about. This seems to
indicate that you should again think about what sprintf()
actually does, i.e. producing a string from the rest of
the arguments, and that it's your resonsibility to supply
it with the memory (via the first argument) it needs to
put that string into.
Post by DFS
srand(time(NULL));
sprintf(randJob ,"%s", jobs [rand()%jobscount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
}
There doesn't seen to be any good reason here for using
sprintf() at all. All you want to do seems to be to out-
put the results, so your whole loop can bxse shortened to

srand(time(NULL));
for (i = 0; i < atoi(argv[1]); i++)
printf("%s, %d, %s\n", names[rand() % namescount],
rates[rand() % ratescount],
jobs[rand() % jobscount]);

Regards, Jens
--
\ Jens Thoms Toerring ___ ***@toerring.de
\__________________________ http://toerring.de
DFS
2017-05-13 12:59:40 UTC
Permalink
Post by Jens Thoms Toerring
There doesn't seen to be any good reason here for using
sprintf() at all. All you want to do seems to be to out-
put the results, so your whole loop can bxse shortened to
srand(time(NULL));
for (i = 0; i < atoi(argv[1]); i++)
printf("%s, %d, %s\n", names[rand() % namescount],
rates[rand() % ratescount],
jobs[rand() % jobscount]);
Regards, Jens
Thanks. That's perfect.

If I did want to use sprintf, just for string handling and getting the
data into variables, why doesn't the below work?

------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

int main(int argc, char *argv[])
{

int i;
char *randName[2];
int randRate[8];
char *randJob[11];

char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};

int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);

srand(time(NULL));
for(i=0;i<atoi(argv[1]);i++)
{
sprintf(randName, "%s", names[rand() % namescount]);
sprintf(randRate, "%d", rates[rand() % ratescount]);
sprintf(randJob , "%s", jobs [rand() % jobscount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
}

return 0;
}
------------------------------------------------------------

It compiles with 3 warnings:
26: warning: assignment from incompatible pointer type
27: warning: assignment from incompatible pointer type
28: warning: assignment from incompatible pointer type

The output for names and jobs seems right, but the int variable isn't.

$ getrandoms 10
A, 1310392, architect
B, 1310392, programmer
E, 1310392, DBA
B, 1310392, DBA
E, 1310392, contractor
D, 1310392, programmer
B, 1310392, DBA
B, 1310392, analyst
A, 1310392, analyst
E, 1310392, contractor
bartc
2017-05-13 13:15:49 UTC
Permalink
Post by DFS
If I did want to use sprintf, just for string handling and getting the
data into variables, why doesn't the below work?
------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i;
char *randName[2];
int randRate[8];
char *randJob[11];
sprintf(randName, "%s", names[rand() % namescount]);
sprintf(randRate, "%d", rates[rand() % ratescount]);
sprintf(randJob , "%s", jobs [rand() % jobscount]);
You're still not calling sprintf properly.

What's the significance of the 2, 8, and 11 in those arrays? sprintf
expects a character array, either char[] or an initialised char*, but
you're passing char*[] and int[]. Some pointer of sorts will be passed,
but the wrong one (hence the warnings), and probably not to what you expect.

Try:

char randName[100];
char randRate[100];
char randJob[100];

The 100 is just some way of ensuring a big enough destination buffer.
Post by DFS
printf("%s, %d, %s\n",randName, randRate, randJob);
And print using all %s.

randRate is now a char buffer, but in yours, you were printing randRate
(which was a int array which becomes an int* in an expression), as a number.
--
bartc
Gareth Owen
2017-05-13 13:19:06 UTC
Permalink
Post by DFS
int main(int argc, char *argv[])
{
int i;
char *randName[2];
This is an array of 2 unitialised pointers, that never get initialised.
You want

char randname[2]; /* 2 bytes of storage for writing a letter and a NULL-byte */
Post by DFS
int randRate[8];
char randRate[3]; /* you're writing a string representation of an int,
so you need a string / array of chars to write it
to - 3 bytes for two digits and NULL-byte*/
Post by DFS
char *randJob[11];
char randJob[11]; /* 11 bytes of storage */
DFS
2017-05-13 15:06:45 UTC
Permalink
Post by Gareth Owen
Post by DFS
int main(int argc, char *argv[])
{
int i;
char *randName[2];
This is an array of 2 unitialised pointers, that never get initialised.
You want
char randname[2]; /* 2 bytes of storage for writing a letter and a NULL-byte */
Post by DFS
int randRate[8];
char randRate[3]; /* you're writing a string representation of an int,
so you need a string / array of chars to write it
to - 3 bytes for two digits and NULL-byte*/
Post by DFS
char *randJob[11];
char randJob[11]; /* 11 bytes of storage */
Thanks Bart.

What I intended to do from the start was not just print, but to put
random char data into char variable(s), and random int data into int
variable(s). Then I could use the variables to build SQL strings or for
other uses.

This seems to work:
--------------------------------------------------------------------
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
int i;
char randName[2];
int randRate=0;
char randJob[11];

char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};

int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);

srand(time(NULL));
for(i=0;i<atoi(argv[1]);i++)
{
sprintf(randName, "%s", names[rand() % namescount]);
randRate = rates[rand() % ratescount];
sprintf(randJob , "%s", jobs [rand() % jobscount]);

printf("%s, %d, %s\n",randName, randRate, randJob);
}

return 0;
}
--------------------------------------------------------------------

$ tcc getrandoms.c -o getrandoms.exe

(clean compile)

$ getrandoms 10
A, 50, contractor
B, 20, architect
E, 10, programmer
C, 10, programmer
D, 10, architect
D, 50, DBA
A, 40, contractor
E, 40, DBA
B, 30, architect
B, 40, contractor


Do you see ways to improve it? How would you write it?

Thanks
Manfred
2017-05-13 15:38:18 UTC
Permalink
<snip>
Post by DFS
Thanks Bart.
What I intended to do from the start was not just print, but to put
random char data into char variable(s), and random int data into int
variable(s). Then I could use the variables to build SQL strings or for
other uses.
--------------------------------------------------------------------
#include <stdio.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i;
char randName[2];
int randRate=0;
char randJob[11];
The size of these buffers needs to be thoroughly considered:
randName: only if all names are guaranteed to be 1-letter names, and
stay that way, then a 2-char buffer is fine.
randJob: in this example all jobs are max 10-letters long, so an 11-char
buffer works fine, but they are variable length names already now, what
if max length may change in future revisions? bart suggested a 100-char
buffer.
Post by DFS
char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};
int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);
srand(time(NULL));
for(i=0;i<atoi(argv[1]);i++)
{
sprintf(randName, "%s", names[rand() % namescount]);
randRate = rates[rand() % ratescount];
sprintf(randJob , "%s", jobs [rand() % jobscount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
}
return 0;
}
--------------------------------------------------------------------
<snip>
Post by DFS
Do you see ways to improve it? How would you write it?
Thanks
DFS
2017-05-13 17:38:22 UTC
Permalink
Post by Manfred
<snip>
Post by DFS
Thanks Bart.
What I intended to do from the start was not just print, but to put
random char data into char variable(s), and random int data into int
variable(s). Then I could use the variables to build SQL strings or
for other uses.
--------------------------------------------------------------------
#include <stdio.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i;
char randName[2];
int randRate=0;
char randJob[11];
randName: only if all names are guaranteed to be 1-letter names, and
stay that way, then a 2-char buffer is fine.
randJob: in this example all jobs are max 10-letters long, so an 11-char
buffer works fine, but they are variable length names already now, what
if max length may change in future revisions? bart suggested a 100-char
buffer.
Yeah, but for this example I'm OK.

How about this?

----------------------------------------------------------
char *names[] = {"AA","B","CCCCXCCCC","D","E"};
char randName[sizeof(names[0])+1];
or
char randName[sizeof(names[0])+2];
or
char randName[sizeof(names[0])+5];
----------------------------------------------------------

Then the buffers are automatically sized to the largest value in the
array (+1 or +2 or +5 whatever), and there's no 'waste' like there would
be if I used randName[100]?

Output looks OK.

$ getrandoms 10
D, 50, architect
AA, 20, architect
B, 20, DBA
E, 20, analyst
B, 40, programmer
D, 30, analyst
AA, 30, architect
D, 50, analyst
CCCCXCCCC, 20, analyst
D, 40, contractor

Is there anything wrong with that approach to sizing?



I noticed something:
----------------------------------------------------------
given: char *names[] = {"AA","B","CCCCXCCCC","D","E"};

option
1. char randName[sizeof(names[0])+2];
2. char randName[sizeof(names[0])+1];
3. char randName[sizeof(names[0])];
4. char randName[sizeof(names[0])-1];
5. char randName[sizeof(names[0])-2];
----------------------------------------------------------

All options compile cleanly.

Option 1 always run fine.
Option 2 always run fine.
Option 3 always runs but sometimes outputs gibberish in the 3rd var
(randJob)
Option 4 runs once or twice then crashes.
Option 5 crashes first run.

Are options 3,4,5 resulting in what's known as a buffer overflow?




Also:
given char *names[] = {"AA","B","CCCCXACCCC","D","E"};

Why does sizeof(names[0]) return 8 instead of 9?


Thanks
bartc
2017-05-13 18:03:13 UTC
Permalink
Post by DFS
How about this?
----------------------------------------------------------
char *names[] = {"AA","B","CCCCXCCCC","D","E"};
char randName[sizeof(names[0])+1];
or
char randName[sizeof(names[0])+2];
or
char randName[sizeof(names[0])+5];
----------------------------------------------------------
Then the buffers are automatically sized to the largest value in the
array (+1 or +2 or +5 whatever),
Automatically? How does that work?

You examples use the size of name[0], which is a pointer, so will be 4
or 8 bytes, then you seem to add an arbitrary number to that. It has
little to do with the size of the largest string in the table, except it
might just be big enough by chance.

and there's no 'waste' like there would
Post by DFS
be if I used randName[100]?
You can choose any number you like that you know will be comfortably
large enough. The space is local storage in a function, and will be
recovered once you're back outside the function. Note that your machine
will be probably have some multiple of 1000,000,000 bytes available.

However, I showed in my other post that you don't need to use sprintf at
all so you don't even need to allocate 2 bytes.
Post by DFS
----------------------------------------------------------
given: char *names[] = {"AA","B","CCCCXCCCC","D","E"};
option
1. char randName[sizeof(names[0])+2];
2. char randName[sizeof(names[0])+1];
3. char randName[sizeof(names[0])];
4. char randName[sizeof(names[0])-1];
5. char randName[sizeof(names[0])-2];
----------------------------------------------------------
All options compile cleanly.
Option 1 always run fine.
Option 2 always run fine.
Option 3 always runs but sometimes outputs gibberish in the 3rd var
(randJob)
Option 4 runs once or twice then crashes.
Option 5 crashes first run.
Are options 3,4,5 resulting in what's known as a buffer overflow?
Probably, as you're effectively using random numbers for the size of the
buffer.
Post by DFS
given char *names[] = {"AA","B","CCCCXACCCC","D","E"};
Why does sizeof(names[0]) return 8 instead of 9?
8 is the number of bytes of a pointer on your machine, as name[0] has a
pointer type (char*).

But why would you expect 9? names[0] points to a string occupying 3
bytes. The longest string (pointed to by names[2]) requires 11 bytes I
think.
--
bartc
bartc
2017-05-13 15:43:18 UTC
Permalink
Post by DFS
char randName[2];
sprintf(randName, "%s", names[rand() % namescount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
Do you see ways to improve it? How would you write it?
Well, the use of sprintf() doesn't really buy you anything here (other
than learning how to use it). Here, sprintf is effectively just copying
a string from one place to another. So you might as well just use the
original.

For example:

printf ("%s, %d, %s\n", names[rand()%namescount], randRate etc...

If the intention was to simplify the operands to printf, then you can do
it like this (set up a pointer to the original string):

char* randName = names[rand() % namescount];
...
printf("%s, %d, %s\n",randName, randRate, randJob);

With no sprintf.
--
bartc
Barry Schwarz
2017-05-13 14:44:44 UTC
Permalink
Post by DFS
Post by Jens Thoms Toerring
There doesn't seen to be any good reason here for using
sprintf() at all. All you want to do seems to be to out-
put the results, so your whole loop can bxse shortened to
srand(time(NULL));
for (i = 0; i < atoi(argv[1]); i++)
printf("%s, %d, %s\n", names[rand() % namescount],
rates[rand() % ratescount],
jobs[rand() % jobscount]);
Regards, Jens
Thanks. That's perfect.
If I did want to use sprintf, just for string handling and getting the
data into variables, why doesn't the below work?
------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i;
char *randName[2];
int randRate[8];
char *randJob[11];
char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};
int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);
srand(time(NULL));
for(i=0;i<atoi(argv[1]);i++)
{
sprintf(randName, "%s", names[rand() % namescount]);
sprintf(randRate, "%d", rates[rand() % ratescount]);
sprintf(randJob , "%s", jobs [rand() % jobscount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
}
return 0;
}
------------------------------------------------------------
26: warning: assignment from incompatible pointer type
27: warning: assignment from incompatible pointer type
28: warning: assignment from incompatible pointer type
Others have explained why you get these diagnostics. Just because
your compiler calls them warnings does not mean they aren't serious.
Post by DFS
The output for names and jobs seems right, but the int variable isn't.
Why are you executing code that does not compile cleanly? You should
never do so unless you *thoroughly* understand what the diagnostics
are trying to tell you.
Post by DFS
$ getrandoms 10
A, 1310392, architect
Welcome to the world of undefined behavior. The most pernicious form
of undefined behavior is to appear to work as you intended.

Your system has led you astray in 2/3 of you output. The remaining
1/3 that you recognize to be incorrect is a clue that your
understanding of the diagnostics is incomplete.
Post by DFS
B, 1310392, programmer
E, 1310392, DBA
B, 1310392, DBA
E, 1310392, contractor
D, 1310392, programmer
B, 1310392, DBA
B, 1310392, analyst
A, 1310392, analyst
E, 1310392, contractor
--
Remove del for email
DFS
2017-05-13 15:25:48 UTC
Permalink
Post by Barry Schwarz
Post by DFS
26: warning: assignment from incompatible pointer type
27: warning: assignment from incompatible pointer type
28: warning: assignment from incompatible pointer type
Others have explained why you get these diagnostics. Just because
your compiler calls them warnings does not mean they aren't serious.
Post by DFS
Why are you executing code that does not compile cleanly? You should
never do so unless you *thoroughly* understand what the diagnostics
are trying to tell you.
Welcome to the world of undefined behavior. The most pernicious form
of undefined behavior is to appear to work as you intended.
Your system has led you astray in 2/3 of you output. The remaining
1/3 that you recognize to be incorrect is a clue that your
understanding of the diagnostics is incomplete.
Thanks for the stern lesson, Professor.

Below is my 'final working version', which compiles cleanly and runs
just fine. See any issues?


--------------------------------------------------------------------
#include <stdio.h>
#include <time.h>

int main(int argc, char *argv[])
{
int i;
char randName[2];
int randRate=0;
char randJob[11];

char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};

int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);

srand(time(NULL));
for(i=0;i<atoi(argv[1]);i++)
{
sprintf(randName, "%s", names[rand() % namescount]);
randRate = rates[rand() % ratescount];
sprintf(randJob , "%s", jobs [rand() % jobscount]);

printf("%s, %d, %s\n",randName, randRate, randJob);
}

return 0;
}
--------------------------------------------------------------------


Thanks
Ben Bacarisse
2017-05-13 18:23:57 UTC
Permalink
Post by DFS
Post by Barry Schwarz
Post by DFS
26: warning: assignment from incompatible pointer type
27: warning: assignment from incompatible pointer type
28: warning: assignment from incompatible pointer type
Others have explained why you get these diagnostics. Just because
your compiler calls them warnings does not mean they aren't serious.
Post by DFS
Why are you executing code that does not compile cleanly? You should
never do so unless you *thoroughly* understand what the diagnostics
are trying to tell you.
Welcome to the world of undefined behavior. The most pernicious form
of undefined behavior is to appear to work as you intended.
Your system has led you astray in 2/3 of you output. The remaining
1/3 that you recognize to be incorrect is a clue that your
understanding of the diagnostics is incomplete.
Thanks for the stern lesson, Professor.
Below is my 'final working version', which compiles cleanly and runs
just fine. See any issues?
I would prefer it not to compile clean since it has a small
compiler-delectable problem. You've forgotten to include stdlib so
rand, srand and atoi are all being called without a prototype and you
are relying on the (now very old) rule that an function undeclared
function f is assume to be declared int f(). That's not even allowed in
modern C (i.e. you must get a diagnostic if you compile as C99 or C11).
Post by DFS
--------------------------------------------------------------------
#include <stdio.h>
#include <time.h>
int main(int argc, char *argv[])
{
int i;
char randName[2];
int randRate=0;
char randJob[11];
char *names[] = {"A","B","C","D","E"};
int rates[] = {10,20,30,40,50};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};
int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);
srand(time(NULL));
for(i=0;i<atoi(argv[1]);i++)
{
sprintf(randName, "%s", names[rand() % namescount]);
randRate = rates[rand() % ratescount];
sprintf(randJob , "%s", jobs [rand() % jobscount]);
printf("%s, %d, %s\n",randName, randRate, randJob);
}
return 0;
}
--------------------------------------------------------------------
This has the look of working too hard, though maybe you plan some future
changes that make this work pay off. Is there anything wrong with just
printing the chosen values:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char *argv[])
{
char *names[] = {"A", "B", "C", "D", "E"};
int rates[] = {10, 20, 30, 40, 50};
char *jobs[] = {"programmer", "DBA", "analyst", "architect", "contractor"};

int namescount = sizeof(names) / sizeof(names[0]);
int ratescount = sizeof(rates) / sizeof(rates[0]);
int jobscount = sizeof(jobs) / sizeof(jobs [0]);

if (argc > 1) {
srand(time(NULL));
for(int i = 0; i < atoi(argv[1]); i++)
printf("%s, %d, %s\n",
names[rand() % namescount],
rates[rand() % ratescount],
jobs[rand() % jobscount]);
}
return 0;
}
--
Ben.
Keith Thompson
2017-05-13 20:58:51 UTC
Permalink
***@toerring.de (Jens Thoms Toerring) writes:
[...]
Post by Jens Thoms Toerring
There doesn't seen to be any good reason here for using
sprintf() at all. All you want to do seems to be to out-
put the results, so your whole loop can bxse shortened to
srand(time(NULL));
for (i = 0; i < atoi(argv[1]); i++)
printf("%s, %d, %s\n", names[rand() % namescount],
rates[rand() % ratescount],
jobs[rand() % jobscount]);
Note that the order of evaluation of the three rand() calls is
unspecified, though it is guaranteed to be called three times.

In the particular case of rand(), that probably doesn't matter,
but it's something to keep in mind. (And it could be significant
if you call srand() with a fixed seed to get a consistent sequence
of pseudo-random numbers, though it won't be consistent across
implementations.)
--
Keith Thompson (The_Other_Keith) kst-***@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
Jens Thoms Toerring
2017-05-13 23:43:34 UTC
Permalink
Post by Keith Thompson
[...]
Post by Jens Thoms Toerring
There doesn't seen to be any good reason here for using
sprintf() at all. All you want to do seems to be to out-
put the results, so your whole loop can bxse shortened to
srand(time(NULL));
for (i = 0; i < atoi(argv[1]); i++)
printf("%s, %d, %s\n", names[rand() % namescount],
rates[rand() % ratescount],
jobs[rand() % jobscount]);
Note that the order of evaluation of the three rand() calls is
unspecified, though it is guaranteed to be called three times.
In the particular case of rand(), that probably doesn't matter,
but it's something to keep in mind. (And it could be significant
if you call srand() with a fixed seed to get a consistent sequence
of pseudo-random numbers, though it won't be consistent across
implementations.)
There are other issues as well, like using only the lower
bits of what rand() returns (that are known to usually be
less "random" than the upper ones). But I guess that's, at
least at the moment, not what the OP will care about a lot;-)

Best regards, Jens
--
\ Jens Thoms Toerring ___ ***@toerring.de
\__________________________ http://toerring.de
Tim Rentsch
2017-05-14 20:43:06 UTC
Permalink
Post by Jens Thoms Toerring
Post by Keith Thompson
[...]
Post by Jens Thoms Toerring
There doesn't seen to be any good reason here for using
sprintf() at all. All you want to do seems to be to out-
put the results, so your whole loop can bxse shortened to
srand(time(NULL));
for (i = 0; i < atoi(argv[1]); i++)
printf("%s, %d, %s\n", names[rand() % namescount],
rates[rand() % ratescount],
jobs[rand() % jobscount]);
Note that the order of evaluation of the three rand() calls is
unspecified, though it is guaranteed to be called three times.
In the particular case of rand(), that probably doesn't matter,
but it's something to keep in mind. (And it could be significant
if you call srand() with a fixed seed to get a consistent sequence
of pseudo-random numbers, though it won't be consistent across
implementations.)
There are other issues as well, like using only the lower
bits of what rand() returns (that are known to usually be
less "random" than the upper ones). [...]
The program given earlier does not in fact have that
property. A slightly different program could have it,
but the one actually given does not.
DFS
2017-05-16 00:18:35 UTC
Permalink
Thanks for your help guys.

That question about sprintf() was related to this program I wrote
yesterday, which does performance tests on the PostgreSQL dbms.

usage: progname baserows exponent
ex: bigdata 1000 10

It will add baserows of random data, then copy it exponent times
Ex: 1000 10 means you end up with 1000*(2^10) = 1024000 rows

------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <C:\Program Files\PostgreSQL\9.6\include\libpq-fe.h>
#include <Windows.h>

// compile on Windows:
// copy libpq.dll to source directory
// tcc bigdata.c libpq.dll -o bigdata.exe

LARGE_INTEGER
frequency,startMaster,startDrop,startRows,startDistinct,start,end;

double elapsedtime(LARGE_INTEGER startingtimer)
{
QueryPerformanceCounter(&end);
return (end.QuadPart - startingtimer.QuadPart) /
(double)frequency.QuadPart;
}

int main(int argc, char *argv[])
{

QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&startMaster);

//vars
int i=0,cnt1=0,cnt2=0;
PGresult *rs;
char cSQL[200];
int colcount = 4;
char *columns[] = {"HIREDATE","REG","SALARY","JOB"};
char *display[] = {"Hire Dates","Regs","Salaries","Jobs"};

//random data sources
char *regs[] = {"Al","Bill","Chris","Diana","Evan"};
int salary[] = {100,150,200,250,300};
char *jobs[] = {"programmer","DBA","analyst","architect","contractor"};

//char *regs[] = {"Al","Bill","Chris","Diana","Evan"};
//int salary[] = {100,150,200,250,300};
//char *jobs[] =
{"programmer","DBA","analyst","architect","contractor"};

//db connect, drop table, recreate table
QueryPerformanceCounter(&startDrop);
char *conninfo = "host='localhost' dbname='COLATEST' user='COLA'
password='evermore'";
PGconn *conn = PQconnectdb(conninfo);
PQexec(conn, "BEGIN TRANSACTION;");
PQexec(conn, "DROP TABLE IF EXISTS BIGDATA;");
PQexec(conn, "CREATE TABLE BIGDATA (ROWSID SERIAL PRIMARY KEY,
HIREDATE DATE NOT NULL, REG VARCHAR(15) NOT NULL,SALARY INTEGER NOT
NULL,JOB VARCHAR(20) NOT NULL);");
PQexec(conn, "COMMIT;");
printf("%.2fs to drop and recreate table\n",elapsedtime(startDrop));

//show counts of random source data
int regcount = sizeof(regs) / sizeof(regs[0]);
int salarycount = sizeof(salary) / sizeof(salary[0]);
int jobcount = sizeof(jobs) / sizeof(jobs[0]);
printf("Random Data: 365 Hire Dates, %d Regs, %d Salaries, %d
Jobs\n",regcount,salarycount,jobcount);

//inputs
int baserows = strtol(argv[1], NULL, 10);
int exponent = strtol(argv[2], NULL, 10);

QueryPerformanceCounter(&startRows);

//add base rows
QueryPerformanceCounter(&start);
struct tm sdt = {0,0,0,1,0,(2017-1900)}; // starting date of 1/1/2017
time_t sdts = mktime(&sdt); //convert start date/time to seconds
since epoch
PQexec(conn, "BEGIN TRANSACTION;");
srand(time(NULL));
for(i=0; i<baserows; i++)
{
time_t randSecs = sdts + (86400 * (rand() % 365));
char* randDate = asctime(gmtime(&randSecs));
char* randReg = regs [rand() % regcount];
int randSalary = salary[rand() % salarycount];
char* randJob = jobs [rand() % jobcount];
sprintf(cSQL,"INSERT INTO BIGDATA (HIREDATE,REG,SALARY,JOB)
VALUES('%s','%s',%d,'%s');",randDate,randReg,randSalary,randJob);
PQexec(conn, cSQL);
}
PQexec(conn, "COMMIT;");
rs = PQexec(conn, "SELECT COUNT(ROWSID) FROM BIGDATA;");
cnt1 = strtol(PQgetvalue(rs,0,0),NULL,10);
printf("added %d rows in %.2fs (total = %d rows)\n",cnt1,
elapsedtime(start),cnt1);

//copy all existing rows: row count doubles each loop
PQexec(conn, "BEGIN TRANSACTION;");
for(i=0; i < exponent; i++)
{
QueryPerformanceCounter(&start);
PQexec(conn, "INSERT INTO BIGDATA (HIREDATE,REG,SALARY,JOB) SELECT
HIREDATE,REG,SALARY,JOB FROM BIGDATA;");
rs = PQexec(conn, "SELECT COUNT(ROWSID) FROM BIGDATA;");
cnt2 = strtol(PQgetvalue(rs,0,0),NULL,10);
printf("%d. added %d rows in %.2fs (total = %d rows)\n",i+1,cnt2-cnt1,
elapsedtime(start),cnt2);
cnt1 = cnt2;
}
PQexec(conn, "COMMIT;");
printf("%.2fs to add all data\n",elapsedtime(startRows));

//create indexes
QueryPerformanceCounter(&start);
PQexec(conn,"CREATE INDEX IDXHIREDATE ON BIGDATA (HIREDATE);");
PQexec(conn,"CREATE INDEX IDXREG ON BIGDATA (REG) ;");
PQexec(conn,"CREATE INDEX IDXSALARY ON BIGDATA (SALARY) ;");
PQexec(conn,"CREATE INDEX IDXJOB ON BIGDATA (JOB) ;");
printf("%.2fs to create indexes\n",elapsedtime(start));

//count distinct values in each column
QueryPerformanceCounter(&start);
printf("Random data contains:");
for(i = 0; i < colcount; i++)
{
sprintf(cSQL,"SELECT COUNT(%s) FROM (SELECT DISTINCT %s FROM BIGDATA)
AS CNT;",columns[i],columns[i]);
rs = PQexec(conn,cSQL);
printf(" %s %s",PQgetvalue(rs,0,0),display[i]);
}
printf("\n%.2fs to count distinct\n",elapsedtime(start));

//get db size
rs = PQexec(conn, "SELECT
pg_size_pretty(pg_database_size(current_database())) AS dbsize");
printf("db size is %s\n",PQgetvalue(rs,0,0));

//close
PQclear(rs);
PQfinish(conn);

double elapsed = elapsedtime(startMaster);
printf("Finished: %.2fs total (%.2fm)",elapsed,elapsed/60);

return 0;
}

Loading...