patterncModerate
Random String generator in C
Viewed 0 times
randomstringgenerator
Problem
I created this small function just to practice C code. It's a simple random string generator.
The code seems to work ok.
Any ideas, improvements or bugs?
I added the
EDIT:
I have changed the code to this:
I know that in the
#include
#include
char *randstring(int length) {
static int mySeed = 25011984;
char *string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-#'?!";
size_t stringLen = strlen(string);
char *randomString = NULL;
srand(time(NULL) * length + ++mySeed);
if (length < 1) {
length = 1;
}
randomString = malloc(sizeof(char) * (length +1));
if (randomString) {
short key = 0;
for (int n = 0;n < length;n++) {
key = rand() % stringLen;
randomString[n] = string[key];
}
randomString[length] = '\0';
return randomString;
}
else {
printf("No memory");
exit(1);
}
}The code seems to work ok.
Any ideas, improvements or bugs?
I added the
mySeed var so that if I call it twice with the same length it doesn't give me the same exact string.EDIT:
I have changed the code to this:
char *randstring(size_t length) {
static char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789,.-#'?!";
char *randomString = NULL;
if (length) {
randomString = malloc(sizeof(char) * (length +1));
if (randomString) {
for (int n = 0;n < length;n++) {
int key = rand() % (int)(sizeof(charset) -1);
randomString[n] = charset[key];
}
randomString[length] = '\0';
}
}
return randomString;
}I know that in the
sizeof(charset) you don't have to use the (). You only need them when using sizeof with types, but it's just out of habit.Solution
Your function is nice but has a few issues, the main one being that it
should not call
just once. This seeds the random number generator, which need only be done
once.
A minor issue is that
It should be
long name.
On failing to allocate memory for the string, I would prefer to see a NULL
return than an
perhaps in the caller, not here. I would be inclined to avoid the
possibility of such an error but passing in the buffer and its length
instead of allocating.
Some minor points: sizeof(char) is 1 by definition and using
is used and I would leave a space after the ; in the for loop definition.
Note also that using
is random - that is not what
Here is how I might do it:
Edit July 31 23:07UTC
Why would I write the function to take a buffer instead of allocating the
string inside the function?
Returning dynamically allocated strings works fine. And if the memory is
later freed there is no problem. But writing this sort of function is a great
way to leak memory, for example if the caller doesn't know the memory must be
freed or forgets to free memory, or even if he frees it in the main path but
forgets to free it in other paths etc.
Memory leaks in a desktop applications might not be fatal, but leaks in an
embedded system will lead eventually to failure. This can be serious,
depending upon the system involved. In many embedded systems, dynamic
allocation is often not allowed or is at least best avoided.
Although it certainly is common not to know the size of strings or buffers
at compile time, the opposite is also often true. It is often possible to
write code with fixed buffer sizes. I always prefer this option if possible
so I would be reluctant to use your allocating function. Perhaps it is better
to add a wrapper to a non-allocating function for those cases where you really
must allocate dynamically (for example when the random string has to outlive the calling context):
should not call
srand. srand should be called elsewhere (eg in main)just once. This seeds the random number generator, which need only be done
once.
A minor issue is that
string is badly named - charset might be better.It should be
const and you then need not call strlen to find its lengthsizeof charset -1 is enough. For me, randomString is an unnecessarilylong name.
On failing to allocate memory for the string, I would prefer to see a NULL
return than an
exit. If you want an error message, use perror, butperhaps in the caller, not here. I would be inclined to avoid the
possibility of such an error but passing in the buffer and its length
instead of allocating.
Some minor points: sizeof(char) is 1 by definition and using
short forkey is pointless - just use int. Also key should be defined where itis used and I would leave a space after the ; in the for loop definition.
Note also that using
rand() % n assumes that the modulo divisionis random - that is not what
rand promises.Here is how I might do it:
static char *rand_string(char *str, size_t size)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK...";
if (size) {
--size;
for (size_t n = 0; n < size; n++) {
int key = rand() % (int) (sizeof charset - 1);
str[n] = charset[key];
}
str[size] = '\0';
}
return str;
}Edit July 31 23:07UTC
Why would I write the function to take a buffer instead of allocating the
string inside the function?
Returning dynamically allocated strings works fine. And if the memory is
later freed there is no problem. But writing this sort of function is a great
way to leak memory, for example if the caller doesn't know the memory must be
freed or forgets to free memory, or even if he frees it in the main path but
forgets to free it in other paths etc.
Memory leaks in a desktop applications might not be fatal, but leaks in an
embedded system will lead eventually to failure. This can be serious,
depending upon the system involved. In many embedded systems, dynamic
allocation is often not allowed or is at least best avoided.
Although it certainly is common not to know the size of strings or buffers
at compile time, the opposite is also often true. It is often possible to
write code with fixed buffer sizes. I always prefer this option if possible
so I would be reluctant to use your allocating function. Perhaps it is better
to add a wrapper to a non-allocating function for those cases where you really
must allocate dynamically (for example when the random string has to outlive the calling context):
char* rand_string_alloc(size_t size)
{
char *s = malloc(size + 1);
if (s) {
rand_string(s, size);
}
return s;
}Code Snippets
static char *rand_string(char *str, size_t size)
{
const char charset[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJK...";
if (size) {
--size;
for (size_t n = 0; n < size; n++) {
int key = rand() % (int) (sizeof charset - 1);
str[n] = charset[key];
}
str[size] = '\0';
}
return str;
}char* rand_string_alloc(size_t size)
{
char *s = malloc(size + 1);
if (s) {
rand_string(s, size);
}
return s;
}Context
StackExchange Code Review Q#29198, answer score: 14
Revisions (0)
No revisions yet.