Sorting an array of structs in C - c

We were given an assignment in class, to sort array of structs. After the assignment was handed in we discussed doing the sorting by using pointers of arrays to sort it as it was more efficient than the way most people had done it.
I decided to try and do it this way as well, however I'm running into some issues that I haven't been able to solve.
http://pastebin.com/Cs3y39yu
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
typedef struct stage2{//standard dec of the struct field
char need;
double ring;
char fight[8];
int32_t uncle;
char game;
double war;
int8_t train;
uint32_t beds;
float crook;
int32_t feast;
int32_t rabbits;
int32_t chin;
int8_t ground;
char veil;
uint32_t flowers;
int8_t adjustment;
int16_t pets;
} stage2;
void usage(){//usage method to handle areas
fprintf(stderr,"File not found\n");//prints to stderr
exit(1);//exits the program
}
int needS(const void *v1, const void *v2)
{
const stage2 *p1 = v1;
const stage2 *p2 = v2;
printf("%c %c \n",p1->need,p2->need);
return 0;
}
int main(int argc, char** argv){
if(argc != 3){//checks for a input files, only 1
usage();//if not runs usage
}
int structSize = 60;//size of structs in bytes, sizeof() doesnt return correct val
char* fileName = argv[1]; //pull input filename
FILE *file = fopen(fileName, "r");//opens in read mode
fseek(file, 0, SEEK_END); //goes to end of file
long fileSize = ftell(file); //saves filesize
char *vals = malloc(fileSize); //allocates the correct size for array based on its filesize
fseek(file, 0, SEEK_SET); //returns to start of file
fread(vals, 1, fileSize, file); //reads the file into char array vals
fclose(file); //closes file
int structAmount = fileSize/structSize; //determines amount of structs we need
stage2 mainArray[structAmount]; //makes array of structs correct size
int j;//loop variables
int i;
printf("need, ring, fight, uncle, game, war, train, beds, crook, feast, rabbits, chin, ground, veil, flowers, adjustment, pets\n");//prints our struct names
for(i = 0; i < structAmount; i ++){//initialises the array vals
mainArray[i].need = *(&vals[0+(i*60)]);
mainArray[i].ring = *((double *)&vals[1+(i*60)]);
for(j = 0;j<9;j++){
mainArray[i].fight[j] = *(&vals[j+9+(i*60)]);
}
mainArray[i].uncle = *((int32_t *)&vals[17+(i*60)]);
mainArray[i].game = *(&vals[21+(i*60)]);
mainArray[i].war = *((double *)&vals[22+(i*60)]);
mainArray[i].train = *((int8_t *)&vals[30+(i*60)]);
mainArray[i].beds = *((uint32_t *)&vals[31+(i*60)]);
mainArray[i].crook = *((float *)&vals[35+(i*60)]);
mainArray[i].feast = *((int32_t *)&vals[39+(i*60)]);
mainArray[i].rabbits = *((int32_t *)&vals[43+(i*60)]);
mainArray[i].chin = *((int32_t *)&vals[47+(i*60)]);
mainArray[i].ground = *((int8_t *)&vals[51+(i*60)]);
mainArray[i].veil = *(&vals[52+(i*60)]);
mainArray[i].flowers = *((uint32_t *)&vals[53+(i*60)]);
mainArray[i].adjustment = *((int8_t *)&vals[57+(i*60)]);
mainArray[i].pets = *((int16_t *)&vals[58+(i*60)]);
}
for(i = 0; i < structAmount; i ++){//prints
printf("%c, %f, %s, %d, %c, %f, %d, %u, %f, %d, %d, %d, %d, %c, %u, %d, %d \n",
mainArray[i].need,mainArray[i].ring,mainArray[i].fight,mainArray[i].uncle,mainArray[i].game,mainArray[i].war,mainArray[i].train,
mainArray[i].beds,mainArray[i].crook,mainArray[i].feast,mainArray[i].rabbits,mainArray[i].chin,mainArray[i].ground,mainArray[i].veil,
mainArray[i].flowers,mainArray[i].adjustment,mainArray[i].pets);//prints
}
free(vals);//frees the memory we allocated to vals
stage2 *array = malloc(structAmount * structSize);
for(i = 0; i < structAmount; i ++){
array[i] = mainArray[i];
}
printf("Before Sort\n\n");
for(i = 0; i < structAmount; i ++){
printf("%c, %f, %s, %d, %c, %f, %d, %u, %f, %d, %d, %d, %d, %c, %u, %d, %d \n",
array[i].need,array[i].ring,array[i].fight,array[i].uncle,array[i].game,array[i].war,array[i].train,
array[i].beds,array[i].crook,array[i].feast,array[i].rabbits,array[i].chin,array[i].ground,array[i].veil,
array[i].flowers,array[i].adjustment,array[i].pets);//prints
}
qsort(array, structAmount,structSize,needS);
printf("After Sort\n\n");
for(i = 0; i < structAmount; i ++){
printf("%c, %f, %s, %d, %c, %f, %d, %u, %f, %d, %d, %d, %d, %c, %u, %d, %d \n",
array[i].need,array[i].ring,array[i].fight,array[i].uncle,array[i].game,array[i].war,array[i].train,
array[i].beds,array[i].crook,array[i].feast,array[i].rabbits,array[i].chin,array[i].ground,array[i].veil,
array[i].flowers,array[i].adjustment,array[i].pets);//prints
}
FILE *my_file = fopen(argv[2], "wb");
for(i = 0; i < structAmount; i ++){
fwrite(&mainArray[i].need, sizeof(char), 1, my_file);
fwrite(&mainArray[i].ring, sizeof(double), 1, my_file);
fwrite(&mainArray[i].fight, sizeof(char[8]), 1, my_file);
fwrite(&mainArray[i].uncle, sizeof(int32_t), 1, my_file);
fwrite(&mainArray[i].game, sizeof(char), 1, my_file);
fwrite(&mainArray[i].war, sizeof(double), 1, my_file);
fwrite(&mainArray[i].train, sizeof(int8_t), 1, my_file);
fwrite(&mainArray[i].beds, sizeof(uint32_t), 1, my_file);
fwrite(&mainArray[i].crook, sizeof(float), 1, my_file);
fwrite(&mainArray[i].feast, sizeof(int32_t), 1, my_file);
fwrite(&mainArray[i].rabbits, sizeof(int32_t), 1, my_file);
fwrite(&mainArray[i].chin, sizeof(int32_t), 1, my_file);
fwrite(&mainArray[i].ground, sizeof(int8_t), 1, my_file);
fwrite(&mainArray[i].veil, sizeof(char), 1, my_file);
fwrite(&mainArray[i].flowers, sizeof(uint32_t), 1, my_file);
fwrite(&mainArray[i].adjustment, sizeof(int8_t), 1, my_file);
fwrite(&mainArray[i].pets, sizeof(int16_t), 1, my_file);
}
fclose(my_file);
return 0;//return statement
}
There is the link to the code that I have been working on. My main issue is that from what I gather, when using the sorting comparison method needS (line 31) for the first execution of the sort it should return the first field for the first two structs in the array and print them (I am aware that this isn't a valid sorting method but wanted to make sure the variables were what I expected). However that's not what occurs; the p1 variable will print out what I expect however the p2 variable will not. From this point onwards, every use of this will return junk (I think) values.
Is there anything that I'm missing or doing wrong?

Your problem is in this line:
int structSize = 60; //size of structs in bytes, sizeof() doesn't return correct val
You're wrong; sizeof() does return the correct size. Whatever you're doing is bogus. You need to go back to the basics of serialization. You will need to write the data correctly. You should be able to read all the data into the array in a single read operation. If you really have a 60 bytes per record in the input, you have serious issues.
Note that your structure layout in memory wastes 7 bytes on most systems (3 on some) between the char need; and double ring; elements. There's a similar gap between the char game; and double war;, and another gap (usually 3 bytes) between int8_t train; and uint32_t beds;, and another similar gap between (usually 2 bytes this time) between char veil; and uint32_t flowers; (because char veil; is preceded by int8_t ground;, and a gap of 1 between int8_t adjustment; and int16_t pets; — I won't guarantee that I've spotted all the gaps).
To learn more about structure layouts and padding, see Why isn't sizeof for a struct equal to the sum of sizeof of each member? as suggested by paddy.
To minimize the wasted space, the heuristic is to put the members with bigger base types before those with smaller base types. Thus all the double members should come before any of the char members. If a member is an array type, ignore the array and look at the size of the base type. For example, char fight[8]; is best put with the other char members at the end, though given that it is a multiple of 8 bytes, it could stay where it is — but it is simpler to be consistent. Pointers need to be treated as 8 bytes on 64-bit systems, or as 4 bytes on 32-bit systems. Place pointers between the non-pointer types such as long long or double (usually 8 bytes each) and the smaller non-pointer types such as int or uint32_t. The long type is a nuisance; it can be 4 or 8 bytes, depending (it's 4 bytes on Windows, even Windows 64-bit; it is 8 bytes on 64-bit Unix or 4 bytes on 32-but Unix).

The function needS needs to return a value that is appropriate for sorting the items in the array.
int needS(const void *v1, const void *v2)
{
const stage2 *p1 = v1;
const stage2 *p2 = v2;
printf("%c %c \n",p1->need,p2->need);
// Something like:
return (p1->need < p2->need);
}

You have confused the "packed" structure size in your data file with the in-memory structure array that you allocate (by default, struct stage2 will have extra padding to align data types efficiently). This line here is the problem:
stage2 *array = malloc(structAmount * structSize);
It should be:
stage2 *array = malloc(structAmount * sizeof(stage2));
Your call to qsort needs to be updated accordingly too:
qsort(array, structAmount, sizeof(stage2), needS);

In addition to other posters' good answers about comparison functions and structure size, you also don't sort by pointers, which was your initial intention.
In your code, you sort a copy of the whole array of large structs. When sorting by pointer, you create an auxiliary array of pointers to the original array elements and then sort these pointers by way of the data they point to. This will leave the original array intact.
Your comparison function must then treat the void * pointers as pointers to pointers to your struct. Example (with heavily abridged structures) below.
#include <stdio.h>
#include <stdlib.h>
typedef struct stage2 {
int need;
} stage2;
int needS(const void *v1, const void *v2)
{
stage2 *const *p1 = v1;
stage2 *const *p2 = v2;
return ((*p1)->need - (*p2)->need) - ((*p2)->need - (*p1)->need);
}
int main(int argc, char **argv)
{
stage2 mainArray[] = {
{8}, {3}, {5}, {1}, {19}, {-2}, {8}, {0},{0}, {4}, {5}, {1}, {8}
};
int structAmount = sizeof(mainArray) / sizeof(*mainArray);
int i;
stage2 **array = malloc(structAmount * sizeof(*array));
// Assign pointers
for (i = 0; i < structAmount; i++) {
array[i] = &mainArray[i];
}
qsort(array, structAmount, sizeof(*array), needS);
puts("Original");
for (i = 0; i < structAmount; i++) {
printf("%d\n", mainArray[i].need);
}
puts("");
puts("Sorted");
for (i = 0; i < structAmount; i++) {
printf("%d\n", array[i]->need);
}
free(array);
return 0;
}

Related

implement the recognition of mnist datasets, the Segmentation fault (core dumped) is displayed

I want to use C language to implement the recognition of mnist datasets, using a backpropagation algorithm, but when loading the input layer neural units, the Segmentation fault (core dumped) is displayed, here's the code snippet, why, and how to solve it.
#include <stdio.h>
#include <unistd.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#define PATH_TRAIN_IMAGES "../../train-images-idx3-ubyte"
#define PATH_TRAIN_LABELS "../../train-labels-idx1-ubyte"
#define PATH_WEIGHT_DATA2 "../data/data2.weight"
#define PATH_WEIGHT_DATA3 "../data/data3.weight"
#define PATH_BIAS_DATA2 "../data/data2.bias"
#define PATH_BIAS_DATA3 "../data/data3.bias"
#define TRAIN_IMAGES_NUMBER 60000
#define PIXEL 784
#define HIDDEN_UNITS_NUMBER 300
#define OUT_UNITS_NUMBER 10
#define TRAIN_TEST 0
struct Unit
{
// input with weight
float z;
// bias
float b;
// output
float a;
};
float sigmod(float z)
{
return (1 / (1 + exp(-z)));
}
struct Unit* create_unit(float uz, float ub, float ua)
{
struct Unit* unit = (struct Unit*)malloc(sizeof(struct Unit));
unit->z = uz;
unit->b = ub;
unit->a = ua;
return unit;
}
int load_train_labels(char* path_train_labels, unsigned char* ar_label)
{
FILE *fp_label;
int size_label = 0;
fp_label = fopen(path_train_labels, "rb");
fseek(fp_label, 0, SEEK_END);
size_label = ftell(fp_label);
printf("%s size:%d byte\n", path_train_labels, size_label);
rewind(fp_label);
// Starting with the 9th byte
fseek(fp_label,8,SEEK_SET);
unsigned char train_labels_buffer[size_label];
ar_label = (unsigned char*)malloc(sizeof(unsigned char) * size_label - 8);
fread(ar_label, 1, size_label - 8, fp_label);
fclose(fp_label);
return size_label;
}
int load_train_images(char* path_train_images, unsigned char* ar_img)
{
FILE *fp_img;
int size_img = 0;
fp_img = fopen(path_train_images, "rb");
fseek(fp_img, 0, SEEK_END);
size_img = ftell(fp_img);
printf("%s size:%d byte\n", path_train_images, size_img);
rewind(fp_img);
// Starting with the 17th byte, each byte stores the value of one pixel in a picture
fseek(fp_img, 16, SEEK_SET);
ar_img = (unsigned char*)malloc(sizeof(char) * size_img - 16);
fread(ar_img, 1, size_img - 16, fp_img);
fclose(fp_img);
return size_img;
}
int load_data(char* path_data, unsigned char* ar_data)
{
FILE *fp_data;
int size_data;
fp_data = fopen(path_data, "rb");
fseek(fp_data, 0, SEEK_END);
size_data = ftell(fp_data);
fseek(fp_data, 0, SEEK_SET);
ar_data = (unsigned char*)malloc(sizeof(char) * size_data);
printf("%s size:%d byte\n", path_data, size_data);
return size_data;
}
int main(int argc, char *argv[])
{
printf("Loading train labels file.\n");
unsigned char* ar_label;
int size_label;
size_label = load_train_labels(PATH_TRAIN_LABELS, ar_label);
printf("Loading train images file.\n");
unsigned char* ar_img;
int size_img;
size_img = load_train_images(PATH_TRAIN_IMAGES, ar_img);
printf("Loading random weight file.\n");
unsigned char* ar_weight2;
int size_weight2;
size_weight2 = load_data(PATH_WEIGHT_DATA2, ar_weight2);
unsigned char* ar_weight3;
int size_weight3;
size_weight3 = load_data(PATH_WEIGHT_DATA3, ar_weight3);
printf("Loading random bias file.\n");
unsigned char* ar_bias2;
int size_bias2;
size_bias2 = load_data(PATH_BIAS_DATA2, ar_bias2);
unsigned char* ar_bias3;
int size_bias3;
size_bias3 = load_data(PATH_BIAS_DATA3, ar_bias3);
float uz = 0;
float ub = 0;
float ua = 0;
struct Unit* out_units[OUT_UNITS_NUMBER];
for (int t = 0; t < OUT_UNITS_NUMBER; t++)
{
out_units[t] = create_unit(uz, ub, ua);
}
struct Unit* hid_units[HIDDEN_UNITS_NUMBER];
for(int i = 0; i < HIDDEN_UNITS_NUMBER; i++)
{
hid_units[i] = create_unit(uz, ub, ua);
}
struct Unit* in_units[PIXEL] = {NULL};
for(int i = 0; i < PIXEL; i++)
{
in_units[i] = create_unit(uz, ub, ua);
}
/*******************
* load C1 *
*******************/
printf("Loading train...\n");
float C[TRAIN_IMAGES_NUMBER];
for(int i = 0; i < PIXEL; i++)
{
in_units[i]->a = (float)*((ar_img+i*sizeof(char))); //segmentation fault(core dumped)
printf("in_unit[%d] = %f\n", i, in_units[i]->a);
}
for(int i = 0; i < HIDDEN_UNITS_NUMBER; i++)
{
for(int j = 0; j < PIXEL; j++)
{
hid_units[i]->z += in_units[j]->a * ((float)*(ar_weight2+((i*PIXEL+j)*sizeof(float))));
}
hid_units[i]->z += ((float)*(ar_bias2+(i*sizeof(float))));
hid_units[i]->a = sigmod(hid_units[i]->z);
}
for(int i = 0; i < OUT_UNITS_NUMBER; i++)
{
for(int j = 0; j < HIDDEN_UNITS_NUMBER; j++)
{
out_units[i]->z += hid_units[j]->a * ((float)*(ar_weight3+((i*HIDDEN_UNITS_NUMBER+j)*sizeof(float))));
}
out_units[i]->z += ((float)*(ar_bias3 + (i*sizeof(float))));
out_units[i]->a = sigmod(out_units[i]->z);
}
// free(in_units)
free(ar_label);
free(ar_img);
free(ar_weight2);
free(ar_bias2);
free(ar_weight3);
free(ar_bias3);
return 0;
}
Almost all source code was uploaded. I used the gdb debugger, but only showed Program terminated with signal SIGSEGV, Segmentation fault.And I turned on ulimit, but didn't find the core file.
Your pointer-passing is flawed. When calling a function and passing that function a pointer to something, you can alter the data the pointer is pointing to, but not the address of the pointer itself so that it is visible from the caller perspective (only in the callees perspective).
For example, one of your functions signature reads:
int load_data(char* path_data, unsigned char* ar_data)
In that function, you do a
ar_data = (unsigned char*)malloc(sizeof(char) * size_data);
This is fine, but this does not effect, that the caller of the function load_data can access this allocated memory. Instead this memory address is lost as soon as that function returns.
This means, that when you write
unsigned char* ar_label;
int size_label;
size_label = load_train_labels(PATH_TRAIN_LABELS, ar_label);
then after calling the function, ar_label still has its original (uninitialized) value. What you probably meant to do was to write the function signature as (notice the extra asterisks/ampersands in the following):
int load_data(char* path_data, unsigned char** ar_data)
Then, allocate the memory as:
*ar_data = (unsigned char*)malloc(sizeof(char) * size_data);
and use the function as:
unsigned char* ar_label;
int size_label;
size_label = load_train_labels(PATH_TRAIN_LABELS, &ar_label);
This way, you are passing a pointer to a pointer and therefore can alter the address the pointer ar_label points to in the caller. This means, that this way you store the address of the mallocated memory block in the callers pointer variable instead of in a copy of the pointer variable supplied as parameter. And you therefore are allowed to access the memory this pointer points to in the caller afterwards.

Copying unsigned char array to uint32_t, and vice versa

I'm trying to iteratively copy an unsigned char array to a uint_32t variable (in 4 byte blocks), perform some operation on the uint_32t variable, and copy it back to the unsigned char array.
Here's my code:
unsigned char byteArray[len]
for (int i=0; i<len; i+=4) {
uint32_t tmpInt = 0;
memcpy(&tmpInt, byteArray+(i*4), sizeof(uint32_t));
// do some operation on tmpInt here
memcpy((void*)(byteArray+(i*4)), &tmpInt, sizeof(uint32_t));
}
It doesn't work though. What's wrong, and how can I achieve what I want to do?
The problem is that you are adding 4 to i with each iteration and multiplying by 4. You should be using byteArray + i.
Also, as #WeatherVane pointed out below, your loop would be more consistent with a sizeof():
for (int i = 0; i < len; i += sizeof(uint32_t)).
As others pointed out you are doing too much by incrementing i as well as multiplying it by the size of your target.
On top of this
the code shown might run into a buffer overflow issue reading beyond the source array.
the sizeof operator evaluates to size_t not int.
the code repeats defining the size of the target independently several times.
Fixing all, the result might look like this:
unsigned char byte_array[len];
typedef uint32_t target_type;
const size_t s = sizeof (target_type);
for (size_t i = 0; i < (len/s)*s; i += s) {
target_type target;
memcpy(&target, byte_array + i, s);
// do some operation on target here
memcpy(byte_array + i, &target, s);
}
To avoid the typedef just define the target outside of the for-loop:
unsigned char byte_array[len];
{
uint32_t target;
const size_t s = sizeof target;
for (size_t i = 0; i < (len/s)*s; i += s) {
memcpy(&target, byte_array + i, s);
// do some operation on target here
memcpy(byte_array + i, &target, s);
}
}
An equivalent to
byte_array + i
would be
&byte_array[i]
which might be more intuitively to read.
To avoid the "strange" (len/s)*s one could step away from using an index at all, but use a pointer instead:
for (unsigned char p = byte_array; p < byte_array + len; p += s) {
memcpy(&target, p, s);
// do some operation on target here
memcpy(p, &target, s);
}
In my opinion this is a more elegant solution.

Convert serial port data to float in C with union

I'm using a C program on Linux to read data from a serial port.
The data to read comes from Code Composer Studio from the line: UART_writePolling(uartHandle, (uint8_t*) &value, sizeof(float));
value is the float I want to read in C, where value = 1.5.
When I read in the data from the serial port, in C, into a buffer and print with printf("%u\n", (int)buffer[i]);
I get value to be:
0
0
4294967232
63
and when I insert buffer[i] into a.array and print with
printf("%d\n", a.array[i]);
I get value to be:
0
0
-64
63
I've also tried using unions:
unsigned int value = 0;
for (int j = 3; j >= 0; j--){
//value <<= 8;
value = value + (int)a.array[i+8+j];
}
printf("value: %u\n", value);
data.u = value;
printf("(float): %f\n", data.f);
which doesn't give the correct answer.
How can I use union to get the correct data as a float?
Do I need to use <<?
EDIT: better idea of the code
//headers
typedef struct {
int *array;
size_t used;
size_t size;
} Array;
void initArray(Array *a, size_t initialSize) {
a->array = (int *)malloc(initialSize * sizeof(int));
a->used = 0;
a->size = initialSize;
}
... //more functions/code to resize array and free the memory later
union Data {
float f;
unsigned int u;
};
int main(){
union Data data;
//open serial port code
char buffer[1]; /* Buffer to store the data received,
reading one at a time */
Array a;
initArray(&a, 5); /* initialise an array to store the read data
that is read into buffer*/
//while loop to read in data for some amount of time/data
int b_read = 0;
b_read = read(fd, &buffer, sizeof(buffer));
for (int i=0; i<b_read; i++){
printf("%u\n", (int)buffer[i]);
// how the first set of values above were printed
insertArray(&a, buffer[i]);
// also adding the values read to buffer into array a
}
//end while
// close the port
for(int i=0; i<no. of elements in array a; i++){
printf("%d\n", a.array[i]);
// how the second set of results were printed
}
//below is an attempt at using union and <<:
unsigned int value = 0;
for (int j = 3; j >= 0; j--){
//value <<= 8;
value = value + (int)a.array[i+8+j]; //index used is particular to my code, where value is in a specific place in the array
}
printf("value: %u\n", value);
data.u = value;
printf("(float): %f\n", data.f);
//these printfs don't give a reasonable answer
// free memory
return 0;
}
Once the bytes are in buffer starting at offset i, you can reinterpret the bytes as a float with:
float f;
memcpy(&f, buffer+i, sizeof f);
To use a union, you could use:
union { uint32_t u; float f; } x;
x.u = value;
float f = x.f;
However, this requires that value contain all 32 bits that represent the float. When you attempted to construct the value with:
//value <<= 8;
value = value + (int)a.array[i+8+j];
There are two issues. First, value <<= 8 is needed. I presume you tried it first and did not get a correct answer, so you commented it out. However, it is required. Second, this code to insert the bytes one-by-one into value is order-dependent. Once the shift is restored, it will insert greater-addressed bytes into less-significant bits of value. Systems generally arrange bytes in objects in one of two orders: More significant bytes in lower addresses or more significant bytes in greater addresses. We do not know which order your system uses, so we do not know whether your code to insert the greater-addressed bytes in less significant bytes is correct.
Note: The above assumes that the bytes are read and written in the same order, or that issues of endianness have already been handled in other code.
You use printf with %u but cast into a int. So maybe it's not surprising to have this behavior since 2^32 = 4294967296, and 4294967296 - 64 (your second printf result) = 4294967232 (your first printf result).
Just cast into "unsigned" if you use "%u" or cast into "int" if you use "%d".

Small generic programming issue in C

So I'm starting to understand the basics of generic programming in C. I'm currently building a program that says if a value occurs or not in a given sequence of number.
I think that the bug occurs in the cmpValues function. Would anyone point it out? (for example, for want=4 and v={1,2,3,4,5}, the program says that want is not in v)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void *search(const void *x, const void *t, int n, int d, int (*cmpValues)(const void *, const void *)){
char *p = (char *)t;
int i;
for(i=0;i<n;++i)
if(cmpValues(x,p+i*d))
return p+i*d;
return NULL;
}
int cmpValues(const void *a, const void *b){
if((char *)a == (char *)b)
return 1;
return 0;
}
int main() {
FILE *f = fopen("datein.txt", "r");
FILE *g = fopen("dateout.txt", "w");
int *v, n, i, want;
fscanf(f, "%d", &n);
v = (int *)malloc(n * sizeof(int));
for(i = 0; i < n; ++i)
fscanf(f, "%d", v + i);
fscanf(f, "%d", &want);
if(search(&want, v, n, sizeof(int), cmpValues))
fprintf(g, "The value %d is found at position %d.\n\n", want, search(&want, v, n, sizeof(int), cmpValues));
else
fprintf(g, "The value does bot occur in the given sequence.\n\n");
return 0;
}
In cmpValues, you are comparing 2 objects pointed by 2 void pointers (i.e. you don't know their type, nor their size). Let's assume we are having ints, and that an int has 4 bytes, which is usually the case.
Just for the sake of it, let's assume that the a pointer has value 0x100 (i.e. points to a int from 0x100 to 0x103, inclusive) and b pointer has a value of 0x104 (i.e. points to the int from 0x104 to 0x107).
Now, you are converting them to char* (char has 1 byte) and compare the value of the pointers. Now, the type of the pointer does not matter in comparisons. In that comparison, you will compare memory addresses (in my example, 0x100 and 0x104). Obviously, the only way the function will return 1 is if the pointers would point to the same variable.
Now, in order to fix it, you should compare the values at the memory addresses pointed by your pointers. However, simply dereferencing the pointers:
*((char *)a) == *((char *)b)
won't be enough, since this would compare just the first byte of a with the first byte of b (under the assumption that char has 1 byte). Also, you can't dereference void*.
So, you need to iterate over your variables and compare them byte by byte (this assumes that you know the size of the data type):
int comp(void *a, void *b, int size) {
// convert a and b to char* (1 byte data type)
char *ca = a;
char *cb = b;
// iterate over size bytes and try to find a difference
for (int i = 0; i < size; i++) {
if (*(ca + i) != *(cb + j)) {
return 0;
}
}
// if no difference has been found, the elements are equal
return 1;
}
side note: you don't need to call cauta twice in main.

Unable to extract byte array value from int value

A union is defined, and given an integer value. The required size of array is estimated. Following the value is defined to the union. However, the byte array values are not able to be printed (ie. the last portion of the following code is not printing).
Given:
union {
unsigned int integer;
//unsigned char byte[4];
unsigned char* byte;
} foo;
In main()
int i;
int numberOfBytes = 1;
int targetValue = 123456789;
int sum = 0;
sum = pow(16, numberOfBytes);
while (sum < targetValue) {
//printf("Trying value: %d \n", (16^numberOfBytes));
numberOfBytes++;
sum += pow(16, numberOfBytes);
}
numberOfBytes++; // add 1 more byte space
printf("Number of Bytes: %d \n", numberOfBytes);
printf("Sum: %d \n", sum);
foo.byte = malloc(sizeof(unsigned char)*numberOfBytes);
if (foo.byte == NULL)
printf("malloc fail\n");
// clear foo
for (i=numberOfBytes; i >= 0;i--) {
foo.byte[i] = 0;
}
foo.integer = targetValue;
printf("Trying value: %d \n", foo.integer);
The following is not printing:
for (i=numberOfBytes; i >= 0;i--) {
printf("%x ", foo.byte[i]);
} printf("\n");
In your union, foo.byte is a pointer to an area of memory. This:
foo.byte = malloc(sizeof(unsigned char)*numberOfBytes);
is setting foo.byte to a pointer to an area of memory which you dynamically allocated. Then this:
foo.integer = targetValue;
is overwriting that pointer with the value.
Then this:
for (i=numberOfBytes; i >= 0;i--) {
printf("%x ", foo.byte[i]);
} printf("\n");
is going to try to de-reference the value of targetValue, which would probably give you a segfault.
The thing is, since you declared targetValue as an int, it will always be sizeof(int) bytes long. There is no reason to dynamically allocate it.
You can change your struct to:
union {
unsigned int integer;
unsigned char byte[sizeof(int)];
} foo;
I assume what you are trying to do is figure out the minimum number of bytes to encode the value of targetValue, and create a union of exactly that size.
Another thing to understand about unions is that they always take the amount of space of their largest member, so even if do dynamically allocate the union, you would have to make it at least sizeof(int) long, otherwise you would corrupt adjacent memory whenever you wrote to the int.
Probably you need to rethink what you are trying to do and approach it from a different angle.

Resources