Related
I need to write a code for my UNI, in which I have to receive 2 arrays of some data (it may be int array or char array or even float array) and compare n characters from pointers in both of the arrays, so far I am stuck with this
*note in other words - I need to write my own memcmp :
int byte_compare(const void *b1,const void *b2,size_t len)
{
char *q1 = (char *)p1;
char *q2 = (char *)p2;
int i;
for (i=0; i<=len*sizeof(*q1) ;i++)
{
if(*q1++ != *q2++)
return 1;
}
return 0;
}
int main()
{
char str1[] = "abcheya";
char str2[] = "gtyheyb";
printf((byte_compare(str1[3],str2[3],3))?"not equal\n":"equal\n");
/*the output is equal*/
int arr1[]={1,2,3,4};
int arr2[]={1,2,7,59};
printf((byte_compare(arr1[0],arr2[0],3))?"not equal\n":"equal\n");
/*the output is also equal although it is not supposed to be*/
return 0;
}
when I compare strings it works just fine, but when I try to compare int or float it wont work properly, please help me.
You should calculate the comparing byte length while passing the len parameter. So, you can use templates for this.
template<typename T>
int byte_compare(const T *b1, const T *b2, size_t len)
{
return memcmp(b1, b2, len * sizeof(T));
}
Edit note : The question is edited and the answer has no more meaning. And it uses C++, not applicable for C lessons. I'm remaining the answer for whose have no restriction to use C++.
Edit: to write own memcmp function
int byte_compare(const void *b1,const void *b2,size_t len)
{
if (len != 0) {
register const unsigned char *p1 = b1, *p2 = b2;
do {
if (*p1++ != *p2++)
return (*--p1 - *--p2);
} while (--len != 0);
}
return (0);
}
You need to pass the size of the objects, not their length:
int byte_compare(const void *b1, const void *b2, size_t size)
{
return memcmp(b1, b2, size);
}
Your instructor probably does not want you to use a library call. So write a byte by byte comparison (aka memcmp).
Get a copy of K&R C (or another book on C), and you will find examples of how to process char(acter) values in a loop.
int byte_compare(const void *b1,const void *b2,size_t len)
{
if( !b1 || !b2 ) return 0; //0 represents false
char* p1=(char*)b1; char* p2=(char*)p2;
for( ; len --> 0; ) {
if( *p1++ != *p2++ ) return 0;
}
return 1;
}
So, my first question here, please be patient with me:
My task is to sort an array of structs (name, surname and another struct for the birthday, which consists of the year, month, day). I have to sort by birthdate and by using qsort.
My problem is, I looked up everything about qsort but i am not quite sure if my implementation is correct since I am new to C. I can create the executable program but it is not giving my any result only Segmentation Fault.
Here is my Code:
#include <stdio.h>
#include <stdlib.h>
typedef int (*compfn) (const void*, const void*);
typedef struct {
unsigned year, month, day;
} date_t;
typedef struct {
char name[32];
char surname[32];
date_t birthday;
}person_t;
typedef struct {
unsigned n;
unsigned cap;
person_t *arr;
} persons_t;
int compare(person_t *a, person_t *b){
if(a->birthday.year!=b->birthday.year){
return a->birthday.year-b->birthday.year;
}else{
if(a->birthday.month!=b->birthday.month){
return a->birthday.month-b->birthday.month;
}else{
return a->birthday.day-b->birthday.day;
}
}
}
int main(int argc, char* argv[])
{
if (argc <= 1) {
fprintf(stderr, "syntax: %s <inputfile>\n", argv[0]);
return 1;
}
FILE* f = fopen(argv[1], "rt");
if (f == NULL) {
fprintf(stderr, "cannot open file %s\n", argv[1]);
return 1;
}
persons_t persons;
persons.n = 0;
persons.cap = 0;
persons.arr = NULL;
person_t p;
while (fscanf(f, "%s %s %4u-%2u-%2u", p.name, p.surname,
&p.birthday.year, &p.birthday.month, &p.birthday.day) == 5) {
if (persons.n == persons.cap) {
persons.cap = persons.cap == 0 ? 1 : 2 * persons.cap;
persons.arr = realloc(persons.arr, persons.cap * sizeof(persons.arr[0]));
}
persons.arr[persons.n++] = p;
}
int nitems = persons.cap*sizeof(persons.arr[0]);
int size = sizeof(persons.arr[0]);
qsort(persons.arr, nitems, size, (compfn)compare);
for (unsigned i = 0; i < persons.n; i++) {
person_t *p = persons.arr + i;
printf("%s %s %4u-%2u-%2u\n",
p->name, p->surname,
p->birthday.year, p->birthday.month, p->birthday.day);
}
fclose(f);
return 0;
}
I hope someone can help me,
Thanks in advance ;)
As far as _t-suffixed identifiers go, according to the C standard they're reserved for the implementation (e.g. your compiler, and/or your standard library). It's very possible that your implementation already has a date_t type, and your code might be causing some kind of mischief. If you wish to avoid subtly and dangerously clashing identifiers wreaking all sorts of havoc, it's probably best to avoid them. Not to worry, you could always use '_s' to denote a struct type instead!
Whenever you're declaring a variable that represents an index within an array, use size_t as the type!
int compare(person_t *a, person_t *b){
...
qsort(persons.arr, nitems, size, (compfn)compare);
According to the qsort manual, the argument given as the comparator function should be an int (*compar)(const void *, const void *), and that's what you've given since you've cast to (compfn). As far as qsort is aware that function accepts two const void * arguments, which might differ in representation to person_t * arguments. This could certainly cause segfaults. Don't lie about the type of compare. Change it to look more like:
int compare(const void *x, const void *y) {
const person_s *a = x, *b = y;
/* ... */
}
... and you won't need the cast or the typedef.
Next, onto return values for that function. I have used implementations where-by lexically illogical return values cause segmentation faults. For example, if a <= b and b <= c, then a <= c, but your code doesn't guarantee this. In fact, using your code it is possible that a <= b, b <= c and a > c. I recommend making sure your code guarantees correspondence between the return value and lexical order. You can do so by returning 1 for greater than, 0 for equal to or -1 for less than.
#define lexical_order(x,y) ((x > y) - (x < y))
int compare(const void *x, const void *b){
const person_s *a = x, *b = y;
return a->birthday.year != b->birthday.year ? lexical_order(a->birthday.year, b->birthday.year)
: a->birthday.month != b->birthday.month ? lexical_order(a->birthday.month, b->birthday.month)
: lexical_order(a->birthday.day, b->birthday.day);
}
I'm sure you're aware that you should be checking the return value of realloc... For example:
void *temp = realloc(persons.arr, persons.cap * sizeof(persons.arr[0]));
if (temp == NULL) { /* If we don't check return value prior *
* to assigning to persons.arr, we *
* might leak some memory... */
puts("Error in realloc");
free(persons.arr);
exit(-1);
}
persons.arr = temp;
Finally, and most importantly (this is probably your error), are you sure about this?
int nitems = persons.cap*sizeof(persons.arr[0]);
If you mean to pass this as the number of items to qsort (which is usual), then I think that should be:
size_t nitems = persons.n;
P.S. In case you missed it the second time, you should probably audit your code to make sure you're using size_t to store array indexes only.
P.P.S. Don't forget to free(persons); at the end of your program, so you don't end up with reports of memory leaks when you use valgrind...
P.P.P.S. valgrind is awesome!
So you are allocating our array by doubling its size whenever needed, using persons.cap, but you are not filling all its elements, are you?
From your code, the actual number of persons is nitems = persons.n, not persons.cap. What if you retry your code with nitems=persons.n?
If you have unfilled elements in your array, it means the strings inside them are arbitrary (i.e person.name), so probably not null-terminated, and the crash will occur when you try to display them.
I have a function which converts a string of an unsigned int to its unsigned int counterpart.
I want to to be able to pass an unsigned type of ANY size to it as the container and specify a limit on how big of a value it is to hold. function prototype is this:
str_to_uint(void *tar, const char *str, const uint64_t lim)
uint64_t *tar is where the unsigned integer will be stored, *str is the string of the number and uint64_t lim is the limit of the size the *tar will be able to hold.
since sizeof(tar) is variable is it safe to cast *tar to an uint64_t * and then contain the converted variable in that? I know that it will always be smaller than the actual type anyway since I check for it with the lim variable.
is such a thing allowed?
basically it would boil down to this
I have a variable of an unsigned type where sizeof(variable) is 1, 2, 3 or 4.
I pass the variable to the function via (void *)&variable.
in the function I cast it to uint64_t * and write the detected variable into it. I make sure the detected variable is able to be written into the variable by checking if it is smaller or equal than lim
is this allowed?
code:
#include <stdio.h>
#include <inttypes.h>
#include <limits.h>
#include <stdlib.h>
static int str_to_uint(uint64_t *tar, const char *str, const uint64_t lim) {
char *eptr = NULL;
unsigned long long int temp = 0;
if (str == NULL) {
printf("str is a NULL pointer\n");
return -1;
}
temp = strtoull(str, &eptr, 10);
if (temp == 0 && eptr == str) {
printf("strtoull() conv err, %s\n", str);
return -1;
} else if (temp > lim) {
printf("strtoull() value to big to contain specified limit, %s\n", str);
return -1;
} else {
*tar = temp;
}
return 0;
}
int main() {
int ret;
uint8_t a;
uint16_t b;
uint32_t c;
uint64_t d;
ret = str_to_uint((void *)&a, "22", UINT8_MAX);
if (ret != 0) {
exit(1);
}
ret = str_to_uint((void *)&b, "22", UINT16_MAX);
if (ret != 0) {
exit(1);
}
ret = str_to_uint((void *)&c, "22", UINT32_MAX);
if (ret != 0) {
exit(1);
}
ret = str_to_uint((void *)&d, "22", UINT64_MAX);
if (ret != 0) {
exit(1);
}
printf("a = %"PRIu8"\nb = %"PRIu16"\nc = %"PRIu32"\nd = %"PRIu64"\n", a, b, c, d);
exit(0);
}
No, of course you can't do that.
If I call your function like this:
uint8_t my_little_value;
str_to_uint(&my_little_value, "4711", sizeof my_little_value);
Then you do
uint64_t *user_value = tar;
*user_value = ...;
Boom, you've overwritten a bunch of bytes you're not allowed to touch. Of course you knew this since I passed you the size of my variable, and you say you "make sure", but I don't see how you intend to do that if your approach is going to be treating tar as a uint64_t *.
I don't see why you can't just return the converted number, like strtoul() already does. That puts the responsibility for dealing with mismatch between storage location and potential precision to represent the converted number on the user (or even on the compiler!) where it belongs. Your proposed API is very error-prone and hard to understand.
At this line of code:
*tar = temp;
You are writing 8 bytes of data to a variable that may be less than 8 bytes in size. You need to handle each size separately, like this for 1 byte:
*(uint8_t *) tar = temp;
here is the prototype:
void *memset(void *s, int c, size_t n)
first im not sure if I have to return something because when I use the memset i do for example
memset(str, 'a', 5);
instead of
str = memset(str, 'a', 5);
here is where I am with my code:
void *my_memset(void *b, int c, int len)
{
int i;
i = 0;
while(b && len > 0)
{
b = c;
b++;
len--;
}
return(b);
}
int main()
{
char *str;
str = strdup("hello");
my_memset(str, 'a', 5);
printf("%s\n", str);
}
I dont want to use array in this function, to better understand pointer and memory, so I dont get 2 things:
- how to copy the int c into a character on my void b pointer
- what condition to use on my while to be sure it stop before a '\0' char
edit: i was wondering is there a way to do this function without casting ?
how to copy the int c into a character on my void b pointer
You convert the void pointer to an unsigned char pointer:
void *my_memset(void *b, int c, int len)
{
int i;
unsigned char *p = b;
i = 0;
while(len > 0)
{
*p = c;
p++;
len--;
}
return(b);
}
what condition to use on my while to be sure it stop before a '\0' char
memset have to trust the length that is passed in. memset needs to work on a general piece of memory, not just a 0 terminated string - so there should not be such a check.
If you anyway would need to check for a 0 byte. you'd do
if (*p == 0) //or if(!*p )
break;
Pointer arithmetic is based on offsetting the pointer by the size of the type it points to. Before you start incrementing that pointer, you should transform it from void* to pointer to char / unsigned char:
void* my_memset(void *s, int c, size_t len) {
unsigned char *dst = s;
while (len > 0) {
*dst = (unsigned char) c;
dst++;
len--;
}
return s;
}
also note that memset returns a pointer to the memory area s, so you should return the original pointer (before you start incrementing it).
The reason functions often return a value is to return an error state to the calling function. In memory related functions it's usually the same pointer as where your result should be (including NULL). In your example you might not want to use the return value of your my_memset function, but usually it's because it can be included in a code evaluation (can't think of a better word for this), e.g.
if(!my_memset((void *)str, 'a', 5))
{
printf("An error occurred in my_memset()\n");
}
or in a macro, e.g. to return pointer to the end of the memory where you copied your char:
#define INIT_MEM_PTR_END(a,x) (my_memset((void *)&(a), (x), sizeof(a)) + sizeof(a))
This is probably not a great example (plus the potential issues if a is already a pointer, etc...), but it shows that you can reuse the result without having to write another couple of lines for this to evaluate the result and so on.
You should also check your pointers before dereferencing them. If for example void *b is NULL, you'll have a segmentation fault.
Nothing wrong with passing in void *, other than the fact that the intention of the function may not be as clear as when passing pointer to a particular data type. Make sure you cast it to something valid though inside. Also this way, the function can be used to set any memory to a particular hex value (through char) or all 0's quite easily.
It would seem like in this case b should be cast to the same type as the value you're trying to copy into it, an int; however, then the len argument becomes unclear, is it size in bytes or number of times c should be copied to the b pointer?
Since in your main() you're copying a char into that memory location, then it's just better to change your c to a char, cast your b to a char* and make len the length in bytes or number of times c should be copied to *b. Avoid ambiguity.
The way you have written it, it will copy c number of times specified by len or until you meet the null character, whichever is shortest/soonest. That's fine, if that's your intention.
void *my_memset(void *b, char c, int len)
{
char *b_char = (char *)b;
if (b == NULL) return NULL;
while(*b_char && len > 0)
{
*b_char = c;
b_char++;
len--;
}
return b; //as this pointer has not changed
}
int main()
{
char *str;
str = strdup("hello");
if (!my_memset((void *)str, 'a', 5))
{
printf("An error occurred in my_memset()\n");
}
else
{
printf("%s\n", str);
}
}
void *my_memset(void *b, int c, int len)
{
if (b == NULL || len <= 0)
return b;
unsigned char *ptr = b;
while(*ptr != '\0' && len--)
{
*ptr++ = (unsigned char)c;
}
return(b);
}
You could use a duff device to have even better performance.
#define DUFF_DEVICE_8(aCount, aAction) \
do { \
int count_ = (aCount); \
int times_ = (count_ + 7) >> 3; \
switch (count_ & 7){ \
case 0: do { aAction; \
case 7: aAction; \
case 6: aAction; \
case 5: aAction; \
case 4: aAction; \
case 3: aAction; \
case 2: aAction; \
case 1: aAction; \
} while (--times_ > 0); \
} \
} while (0)
I tried one implementation like this:
void memset(void *b, int c, int len)
{
char *s = b;
while(len--)
*s++ = c;
}
Can a string be used as array index in C?
Ex:
String Corresponding value
"ONE" 1
"TWO" 2
"FIVE" 5
"TEN" 10
When a string in the above list is passed to the function, the function must return the corresponding value indicated above. Can this be achieved by declaring a constant array with string as index
int *x;
x["ONE"] = 1;
x["TWO"] = 2;
x["FIVE"] = 5;
x["TEN"] = 5;
return x["string received by the function"];
The above logic does not work as expected; is there a workaround to implement the above logic in order to have a string-indexed array?
It might compile, but it won't work.
It's not entirely clear what you're trying to achieve. I think you want an associative array, in which case you should find a library implementation of one.
If you're looking for something more like an enumerated type, and you can rely on C89, look at something like:
enum cardsuit {
CLUBS,
DIAMONDS,
HEARTS,
SPADES
};
If you can't rely on C89, then you should try some typedef trickery.
There are other excellent answers to what you should do, so I thought I'd explain what you are doing and why it's compiling and not working.
In C, array reference is done by having an array or pointer and an integer of some sort. (in x[1], x is the array and 1 is the integer). As long as you're using some integral type, it'll work as you expect.
Suppose you have something that's not an integer. In that case, the C implementation will see if it can convert it to the appropriate type, so you wind up with array and integer. It's cases like this where you get into trouble (and slightly more sophisticated versions of this in C++ have confused more experienced people than you).
In C, a literal string like "one" is of type const char *, meaning pointer to characters you can't change. The actual value is the memory address of where the string actually resides in memory. Normally, you'd pay no attention to this pointer value, and look at the string value, but there's a gotcha here.
In C, any data pointer can be converted to some sort of integer, and will be automatically. Therefore, you've got a string like "one", and its value is whatever number that represents the memory address. Use it where C expects some sort of integer, and it'll get converted to some integral value or other.
Therefore, this is what's happening with x["ONE"]. The C system has to put the string "ONE" somewhere in memory, and it doesn't matter where. It's likely to be somewhere with a fairly large memory address, quite possibly in the billions. When it sees x["ONE"], it tries to convert that value to an integer, and uses it as a subscript. Therefore, you're trying to access the array x far, far beyond its bounds, and that's causing the problem. Either you're trying to use memory you're not allowed to, and the system just stops you, or you're mucking with a chunk of memory you should be leaving alone, and it's likely to fail in some mysterious way later.
You can easily build lookup tables with the function bsearch() provided by stdlib.h. A working example is this:
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#define count(ARRAY) (sizeof(ARRAY)/sizeof(*ARRAY))
struct item
{
const char * name;
int value;
};
static _Bool sorted;
static struct item items[] =
{
{ "one", 1 },
{ "two", 2 },
{ "three", 3 },
{ "ten", 10 }
};
static int compare(const void * p1, const void * p2)
{
return strcmp(*((const char **)p1), *((const char **)p2));
}
int get(const char * name)
{
if(!sorted)
{
qsort(items, count(items), sizeof(*items), compare);
sorted = 1;
}
struct item * item = bsearch(&name, items, count(items), sizeof(*items),
compare);
return item ? item->value : 0;
}
int main(int argc, char ** argv)
{
int i;
for(i = 1; i < argc; ++i)
printf("%i\n", get(argv[i]));
return 0;
}
You will need to write a function that maps strings to integers, or alternatively use enumerations throughout (and then perhaps a function that maps enumerated values to strings).
In general, it's nicer to do the latter: to pass integers, so that the implementation isn't dependent on the details of strings that might be used in the representation. For example, think about how you would manage localization (translation) if ever you need to make those strings palatable to somebody speaking a different language.
What you are looking for is probably the equivalent of an associative array which can't be provided with the same syntactic sugar in C unfortunately without some silly results.
However, what you can provide is a hashmap if your data conforms to key -> value pairs. What you will need is an appropiate hash function.
There's a decent simple example of a hashtable here:
http://www.cl.cam.ac.uk/~cwc22/hashtable/
As already indicated, you need an associative array or hash map or equivalent. One possible source for such code is Hanson's "C Interfaces and Implementations" (code at Google Code - double check licencing terms etc before using it.)
This is an old thread, but I thought this might still be useful for anyone out there looking for an implementation. It doesn't take too much code; I did mine in ~100 lines of without any extra library like Hank Gay suggested. I called it a dictionary since it parallels (sort of) the python datatype. Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
typedef struct hollow_list hollow_list;
struct hollow_list{
unsigned int size;
void *value;
bool *written;
hollow_list *children;
};
//Creates a hollow list and allocates all of the needed memory
hollow_list hollow_list_create(unsigned int size){
hollow_list output;
output = (hollow_list) {.size = size, .value = (void *) 0, .written = calloc(size, sizeof(bool)), .children = calloc(size, sizeof(hollow_list))};
return output;
}
//Frees all memory of associated with a hollow list and its children
void hollow_list_free(hollow_list *l, bool free_values){
int i;
for(i = 0; i < l->size; i++){
hollow_list_free(l->children + i, free_values);
}
if(free_values){
free(l->value);
}
free(l);
}
//Reads from the hollow list and returns a pointer to the item's data
void *hollow_list_read(hollow_list *l, unsigned int index){
if(index == 0){
return l->value;
}
unsigned int bit_checker;
bit_checker = 1<<(l->size - 1);
int i;
for(i = 0; i < l->size; i++){
if(bit_checker & index){
if(l->written[i] == true){
return hollow_list_read(l->children + i, bit_checker ^ index);
} else {
return (void *) 0;
}
}
bit_checker >>= 1;
}
}
//Writes to the hollow list, allocating memory only as it needs
void hollow_list_write(hollow_list *l, unsigned int index, void *value){
if(index == 0){
l->value = value;
} else {
unsigned int bit_checker;
bit_checker = 1<<(l->size - 1);
int i;
for(i = 0; i < l->size; i++){
if(bit_checker & index){
if(!l->written[i]){
l->children[i] = hollow_list_create(l->size - i - 1);
l->written[i] = true;
}
hollow_list_write(l->children + i, bit_checker ^ index, value);
break;
}
bit_checker >>= 1;
}
}
}
typedef struct dictionary dictionary;
struct dictionary{
void *value;
hollow_list *child;
};
dictionary dictionary_create(){
dictionary output;
output.child = malloc(sizeof(hollow_list));
*output.child = hollow_list_create(8);
output.value = (void *) 0;
return output;
}
void dictionary_write(dictionary *dict, char *index, unsigned int strlen, void *value){
void *hollow_list_value;
dictionary *new_dict;
int i;
for(i = 0; i < strlen; i++){
hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
if(hollow_list_value == (void *) 0){
new_dict = malloc(sizeof(dictionary));
*new_dict = dictionary_create();
hollow_list_write(dict->child, (int) index[i], new_dict);
dict = new_dict;
} else {
dict = (dictionary *) hollow_list_value;
}
}
dict->value = value;
}
void *dictionary_read(dictionary *dict, char *index, unsigned int strlen){
void *hollow_list_value;
dictionary *new_dict;
int i;
for(i = 0; i < strlen; i++){
hollow_list_value = hollow_list_read(dict->child, (int) index[i]);
if(hollow_list_value == (void *) 0){
return hollow_list_value;
} else {
dict = (dictionary *) hollow_list_value;
}
}
return dict->value;
}
int main(){
char index0[] = "hello, this is a test";
char index1[] = "hello, this is also a test";
char index2[] = "hello world";
char index3[] = "hi there!";
char index4[] = "this is something";
char index5[] = "hi there";
int item0 = 0;
int item1 = 1;
int item2 = 2;
int item3 = 3;
int item4 = 4;
dictionary d;
d = dictionary_create();
dictionary_write(&d, index0, 21, &item0);
dictionary_write(&d, index1, 26, &item1);
dictionary_write(&d, index2, 11, &item2);
dictionary_write(&d, index3, 13, &item3);
dictionary_write(&d, index4, 17, &item4);
printf("%d\n", *((int *) dictionary_read(&d, index0, 21)));
printf("%d\n", *((int *) dictionary_read(&d, index1, 26)));
printf("%d\n", *((int *) dictionary_read(&d, index2, 11)));
printf("%d\n", *((int *) dictionary_read(&d, index3, 13)));
printf("%d\n", *((int *) dictionary_read(&d, index4, 17)));
printf("%d\n", ((int) dictionary_read(&d, index5, 8)));
}
Unfortunately you can't replicate the list[x] syntax, but this is the best alternative I have come up with.
In "plain C" you can mimic using a string as an index, but not QUITE in the way you seem to be wanting. However, doing so is seldom useful and mostly an excellent way of making your code unreadable. What you seem to be wanting is to be able to use string keys into a dictionary (or "hash table", if you prefer) and there are no built-in data structure for that in C. The exact design would depend on what you want (and, indeed, if this is part of homework, you may not even need to use a full-fledged hash-table implementation but could probably get away with less performant static coding).
An example using a string (OK, a char array) in the "index position) of an a[b] construct:
int main (void)
{
char *str = "This is a test string";
int x;
for (x=0; x < 12; x += 3)
putchar(x[str]);
printf("\n");
return 0;
}
The above is, as far as I can tell, legal C, with a well-defined output (the string "Tss ssi"). It relies on the fact that a[b] is defined to be the same as *(a+b).