turning hash key (unsigned long) to int safely - c

I have a hash function:
unsigned long strhash(char *string)
{
unsigned long hash = 5381;
int c;
while (c = *string++)
{
hash = ((hash << 5) + hash) + c;
}
return hash;
}
and my program calls it like so
char testString[] = "Hello World";
unsigned long hashcode = 0;
hashcode = strhash(testString);
int slot = 0;
slot = hashcode%30;
printf("%d\n", slot);
the module is to module what will be the size of my array
is this safely converting from unsigned long to int?
because it prints out 17 making me feel like it is working but I am unsure

Note: I assume you meant printf("%d\n", slot); in the last statement.
By doing a modulo with 30, you are effectively restricting the hash value to only 30 unique values (0 to 29). This drastically reduces the effectiveness of the hash, as many different strings will be mapped to the same hash value (one out of those 30).
This link gives you a number of alternative hash functions, including an unsigned int version of the djb2 algorithm in your question. Use one of them instead.

Related

Why does this djb2 implementations loop terminate?

A string is terminated by a s single null byte. Since a int is bigger then an char how can the int become 0 and terminate the loop consistenly?
source : http://www.cse.yorku.ca/~oz/hash.html
unsigned long
hash(unsigned char *str)
{
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
Loading an integer from a smaller type does not preserve the bits that the smaller type didn't have; they are cleared (or set by sign-extension, for signed types).
So:
int x = 0xfeefd00d;
x = (char) 1;
leaves the value 1, as an integer, in x, not 0xfeedf001.
When a variable is used in an expression together with variables of different types (like in the assignment in the loop condition), there's an implicit conversion being made. Conversions only convert between types, but if possible keeps the value.
So when you reach the null-terminator in str, it's converted (promoted actually) to an int, keeping the value 0. And 0 is always "false", which ends the loop.

Unsigned integers overflow does not "wrap around"

I read following line from Integer Overflow Wiki:
while unsigned integer overflow causes the number to be reduced modulo
a power of two, meaning that unsigned integers "wrap around" on
overflow.
I have below code where I am trying to create a hash function and got int overflow situation. I tried to mitigate it by using unsigned int but it didn't work and I was able to see negative values.
I know I can handle it other way and it works, as shown in my code comment - Comment 2:. But is it right way and why unsigned int was not wrapping around and overflowing?
int hash(char *word) {
char *temp = word;
unsigned int hash = 0; // Comment 1: I tried to handle int overflow using "unsigned" int.
while (*word != '\0') {
// Comment 2: This works but I do not want to go this way.
//while ((hash * PRIME_MULTIPLIER) < 0) {
// hash = (hash * PRIME_MULTIPLIER) + 2147483647;
//}
hash = hash * PRIME_MULTIPLIER + *word;
word++;
}
printf("Hash for %s is %d\n", temp, hash);
return hash;
}
You're using the wrong format specifier for printf. For an unsigned int, you should be using %u instead of %d.
Also, you should be returning an unsigned int instead of an int.

unsigned char to unsigned char array of 8 original bits

I am trying to take a given unsigned char and store the 8 bit value in an unsigned char array of size 8 (1 bit per array index).
So given the unsigned char A
Id like to create an unsigned char array containing 0 1 0 0 0 0 0 1 (one number per index)
What would be the most effective way to achieve this? Happy Thanksgiving btw!!
The fastest (not sure if that's what you menat by "effective") way of doing this is probably something like
void char2bits1(unsigned char c, unsigned char * bits) {
int i;
for(i=sizeof(unsigned char)*8; i; c>>=1) bits[--i] = c&1;
}
The function takes the char to convert as the first argument and fills the array bits with the corresponding bit pattern. It runs in 2.6 ns on my laptop. It assumes 8-bit bytes, but not how many bytes long a char is, and does not require the input array to be zero-initialized beforehand.
I didn't expect this to be the fastest approach. My first attempt looked like this:
void char2bits2(unsigned char c, unsigned char * bits) {
for(;c;++bits,c>>=1) *bits = c&1;
}
I thought this would be faster by avoiding array lookups, by looping in the natural order (at the cost of producing the bits in the opposite order of what was requested), and by stopping as soon as c is zero (so the bits array would need to be zero-initialized before calling the function). But to my surprise, this version had a running time of 5.2 ns, double that of the version above.
Investigating the corresponding assembly revealed that the difference was loop unrolling, which was being performed in the former case but not the latter. So this is an illustration of how modern compilers and modern CPUs often have surprising performance characteristics.
Edit: If you actually want the unsigned chars in the result to be the chars '0' and '1', use this modified version:
void char2bits3(unsigned char c, unsigned char * bits) {
int i;
for(i=sizeof(unsigned char)*8; i; c>>=1) bits[--i] = '0'+(c&1);
}
You could use bit operators as recommended.
#include <stdio.h>
main() {
unsigned char input_data = 8;
unsigned char array[8] = {0};
int idx = sizeof(array) - 1;
while (input_data > 0) {
array[idx--] = input_data & 1;
input_data /= 2; // or input_data >>= 1;
}
for (unsigned long i = 0; i < sizeof(array); i++) {
printf("%d, ", array[i]);
}
}
Take the value, right shift it and mask it to keep only the lower bit. Add the value of the lower bit to the character '0' so that you get either '0' or '1' and write it into the array:
unsigned char val = 65;
unsigned char valArr[8+1] = {};
for (int loop=0; loop<8; loop++)
valArr[7-loop] = '0' + ((val>>loop)&1);
printf ("val = %s", valArr);

How to convert from integer to unsigned char in C, given integers larger than 256?

As part of my CS course I've been given some functions to use. One of these functions takes a pointer to unsigned chars to write some data to a file (I have to use this function, so I can't just make my own purpose built function that works differently BTW). I need to write an array of integers whose values can be up to 4095 using this function (that only takes unsigned chars).
However am I right in thinking that an unsigned char can only have a max value of 256 because it is 1 byte long? I therefore need to use 4 unsigned chars for every integer? But casting doesn't seem to work with larger values for the integer. Does anyone have any idea how best to convert an array of integers to unsigned chars?
Usually an unsigned char holds 8 bits, with a max value of 255. If you want to know this for your particular compiler, print out CHAR_BIT and UCHAR_MAX from <limits.h> You could extract the individual bytes of a 32 bit int,
#include <stdint.h>
void
pack32(uint32_t val,uint8_t *dest)
{
dest[0] = (val & 0xff000000) >> 24;
dest[1] = (val & 0x00ff0000) >> 16;
dest[2] = (val & 0x0000ff00) >> 8;
dest[3] = (val & 0x000000ff) ;
}
uint32_t
unpack32(uint8_t *src)
{
uint32_t val;
val = src[0] << 24;
val |= src[1] << 16;
val |= src[2] << 8;
val |= src[3] ;
return val;
}
Unsigned char generally has a value of 1 byte, therefore you can decompose any other type to an array of unsigned chars (eg. for a 4 byte int you can use an array of 4 unsigned chars). Your exercise is probably about generics. You should write the file as a binary file using the fwrite() function, and just write byte after byte in the file.
The following example should write a number (of any data type) to the file. I am not sure if it works since you are forcing the cast to unsigned char * instead of void *.
int homework(unsigned char *foo, size_t size)
{
int i;
// open file for binary writing
FILE *f = fopen("work.txt", "wb");
if(f == NULL)
return 1;
// should write byte by byte the data to the file
fwrite(foo+i, sizeof(char), size, f);
fclose(f);
return 0;
}
I hope the given example at least gives you a starting point.
Yes, you're right; a char/byte only allows up to 8 distinct bits, so that is 2^8 distinct numbers, which is zero to 2^8 - 1, or zero to 255. Do something like this to get the bytes:
int x = 0;
char* p = (char*)&x;
for (int i = 0; i < sizeof(x); i++)
{
//Do something with p[i]
}
(This isn't officially C because of the order of declaration but whatever... it's more readable. :) )
Do note that this code may not be portable, since it depends on the processor's internal storage of an int.
If you have to write an array of integers then just convert the array into a pointer to char then run through the array.
int main()
{
int data[] = { 1, 2, 3, 4 ,5 };
size_t size = sizeof(data)/sizeof(data[0]); // Number of integers.
unsigned char* out = (unsigned char*)data;
for(size_t loop =0; loop < (size * sizeof(int)); ++loop)
{
MyProfSuperWrite(out + loop); // Write 1 unsigned char
}
}
Now people have mentioned that 4096 will fit in less bits than a normal integer. Probably true. Thus you can save space and not write out the top bits of each integer. Personally I think this is not worth the effort. The extra code to write the value and processes the incoming data is not worth the savings you would get (Maybe if the data was the size of the library of congress). Rule one do as little work as possible (its easier to maintain). Rule two optimize if asked (but ask why first). You may save space but it will cost in processing time and maintenance costs.
The part of the assignment of: integers whose values can be up to 4095 using this function (that only takes unsigned chars should be giving you a huge hint. 4095 unsigned is 12 bits.
You can store the 12 bits in a 16 bit short, but that is somewhat wasteful of space -- you are only using 12 of 16 bits of the short. Since you are dealing with more than 1 byte in the conversion of characters, you may need to deal with endianess of the result. Easiest.
You could also do a bit field or some packed binary structure if you are concerned about space. More work.
It sounds like what you really want to do is call sprintf to get a string representation of your integers. This is a standard way to convert from a numeric type to its string representation. Something like the following might get you started:
char num[5]; // Room for 4095
// Array is the array of integers, and arrayLen is its length
for (i = 0; i < arrayLen; i++)
{
sprintf (num, "%d", array[i]);
// Call your function that expects a pointer to chars
printfunc (num);
}
Without information on the function you are directed to use regarding its arguments, return value and semantics (i.e. the definition of its behaviour) it is hard to answer. One possibility is:
Given:
void theFunction(unsigned char* data, int size);
then
int array[SIZE_OF_ARRAY];
theFunction((insigned char*)array, sizeof(array));
or
theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(*array));
or
theFunction((insigned char*)array, SIZE_OF_ARRAY * sizeof(int));
All of which will pass all of the data to theFunction(), but whether than makes any sense will depend on what theFunction() does.

Best way to convert unsigned char * to int?

Hello I have an unsigned char * that looks (after printf) like this (it's a SHA-1 hash):
n\374\363\327=\3103\231\361P'o]Db\251\360\316\203
I need to convert this unsigned char * to an unsigned int, what do you think it would be the best way to do it ? I have some ideas, but I'm not a C expert so wanted to see someone else ideas before trying my own stuff.
Why would you need a conversion? It's a 160 bit long digest. Digests are used only in two ways:
You print a digest with something like
for (i = 0; i < 20; ++i) {
printf("%2x", digest[i]);
}
and compare against another digest with something like
for (i = 0, equals = 1; i < 20; ++i) {
if (a[i] != b[i]) {
equals = 0;
}
}
It works just fine the way it is as a 20-byte long array of bytes. You don't have to worry about endianness, word length, nothing.
Well, that's more than 4 bytes, so if your system uses 32 bits for an unsigned int you can't do it without potentially losing information. IOW, it will have to be a hash of some kind.
That's 160 bits, so would be hard to fit in a single unsigned int. However, it'd certainly be possible to fit it into an array of unsigned ints.
Something like this (ugly, makes a couple of assumptions about machine architecture, should probably use CHAR_BITS and a couple of other things compile-time to have the right constants, but should be enough as a proof-of-concept):
unsigned int (*convert)(unsigned char *original)
{
unsigned int *rv = malloc(5*sizeof(unsigned int));
char *tp = original;
for (rvix=0;rvix<5;rvix++) {
rv[rvix] = *(tp++)<<24;
rv[rvix] |= *(tp++)<<16;
rv[rvix] |= *(tp++)<<8;
rv[rvix] |= *(tp++);
}
return rv;
}

Resources