How do I do a word search without using strcmp? - c

int function(char * WordList[], int nSize, char * param_str)
{
int i = 0;
int bFlag = 0;
while(i < nSize && !bFlag)
{
if(WordList[i] == param_str){
return bFlag = 1;
}
i++;
}
return bFlag;
i tried using strcmp and made it work [if(strcmp(WordList[i], param_str) == 0)] but im wondering whats wrong with my current code.

WordList[i] is a pointer
param_str is another pointer.
WordList[i] == param_str tests if the 2 pointers point to the same location.
What these pointers reference is not considered. WordList[i] == param_str is not a string compare, just an address compare.
strcmp(a,b) compares the data at locations a and b.
To do the same, without strcmp(), form your own ...
int my_strcmp(const char *a, const char *b) {
// Pseudo code
while what `a` points to is the same as what `b` points to and `*a` is not 0
advance both pointers
return the sign of the difference of `*a` and `*b`.
}

Related

Adding a number to each element in array using pointers

There is a function, which I wish to add numbers to each element in arrays, with only pointers. But I'm failing it. The main problem is what to do with adding the sum. The pointer results in errors in the while loop.
void f(int *a, const int len) {
const int *pointer = a;
const int *add;
while (pointer < a + len) {
(a + pointer) += add; //this is like a[p], but with pointers, it's not working
++ pointer;
}
}
The following is the original code with the minimal corrections to make it work, and some comments to explain the changes:
void f(int *a, const int len) {
const int add = 101; // must initialize `add` here, since it's `const` and can't be modified later
int *pointer = a; // initialize `pointer` to point to the first element in the array
// can not be `const int *` since `*pointer` must be writeable
while (pointer < a + len) {
*pointer += add; // add `add` to the current element that `pointer` points to
++pointer; // increment `pointer` to point to the next element
}
}
Looking at the while loop, it gets executed len times if len > 0, or not at all if len <= 0. Then the whole function can be rewritten in a more idiomatic C way as follows:
void f(int *ptr, int len) {
const int add = 101;
while (len-- > 0) { // loop 'len' times
*ptr++ += add; // equivalent to `*ptr += add; ptr++;` due to operators precedence
}
}

Bsearch with strings in C

So I'm trying to use the bsearch function in C to do a binary search in an array of strings. For some reason, it always returns NULL. For the compare function of bsearch I didn't use strcmp, I made my own which, surprisingly, works for my manual implementation of the binary search function. I'll explain in a bit, anyway, here's my main code:
int main(){
int n;
scanf("%d", &n);
if(n<=0) qerror();
char ** words = (char **)calloc(n, sizeof(char *));
if(words == NULL) qerror();
int i = 0;
for(;i<n;i++){
words[i] = (char *)calloc(MAX, sizeof(char));
if(words[i] == NULL) qerror();
scanf("%s", words[i]);
}
char seek_word[MAX];
scanf("%s", seek_word);
char ** c = (char **)bsearch(seek_word, words, n, sizeof(char *), &b_compare_words);
if(c == NULL) printf("-1\n");
else printf("%d\n", c - words);
//printf("%d\n", bin_search_string(words, n, seek_word)); //manuelna binarna pretraga
free(words);
return 0;
}
The first part of this code is just creating an array of strings (named words) that contains N strings of the length MAX (which is a macro defined at the beginning). I've tested this part and it works, so that's not the problem.
Afterwards, the seek_word is inputted, which is just the word that we're trying to find in 'words'. The I call the bsearch and as a compare function I used the function that I've created myself. Here's what it looks like:
int compare_words(char * a, char * b){
int i = 0;
while(a[i] && b[i]){
char ac = tolower(a[i]), bc = tolower(b[i]);
if(ac < bc) return -1;
else if (ac > bc) return 1;
i++;
}
return 0;
}
int b_compare_words(const void * a, const void * b){
return compare_words((char *)a, (char *)b);
}
The actual comparison work is done in the compare_words function which I've called from the b_compare_words function where I've just casted the void pointers into char pointers.
And whatever I test this on, I get -1 (meaning the pointer returned by bsearch is NULL).
Now here's the interesting part. Apart from this I've made my own binary search function that does the same thing and it works (you can see the part that I commented out below). The function is called bin_search_string and it looks like this:
int bin_search_string(char ** a, int n, char * x){
int l_index = 0;
int r_index = n-1;
int check_index;
while(l_index <= r_index){
check_index = l_index + (r_index - l_index)/2;
int test = compare_words(x, a[check_index]);
if(test == 0) return check_index;
else if(test < 0) l_index = check_index + 1;
else r_index = check_index - 1;
}
return -1;
}
As you can see, this function uses the same compare_words function that I've also passed to bsearch. But when I test my program using my own function, it really works (returns the index where the string was found).
So, any ideas why the bsearch won't work?
Thanks in advance.

Using qsort() from stdlib.c to sort an array of strings in C according to the 3rd letter in each *char

I have an array of char* like this
aob3l
gou5!
oib1k
llp6d
with every 3rd index a number.
I want to use qsort() to sort that list according to those numbers.
A sorted list would look like this
oib1k
aob3l
gou5!
llp6d
This is how I'm trying to implement it.
qsort(string_mix, (size_t) (k - 1), sizeof(char), compare_at3);
My compare_at3 function looks like this
int compare_at3(const void* a, const void* b){
static int k = 1;
const char *ia = a;
const char *ib = b;
printf("In compare_at3 %d iter\n", k++);
return ((ia[3] - '0') - (ib[3] - '0'));
}
And my question is,
what am I doing wrong to get SIGSEGV segfault errors?
My best guess is that this line const char *ia = a; isn't doing what I think it's doing.
I'm using * in *ia so I can subscript int as its index but maybe *ia isn't the char* like aob3l.
EDIT1: Sorry, I didn't mention what exactly string_mix is.
It's a 2D array of those strings in the question defined like
char* string_mix[MAX_NO_OF_STRINGS]
char s1_formatted[strlen(s1)];
char s2_formatted[strlen(s2)];
formatted(s1, s1_formatted);
formatted(s2, s2_formatted);
char s1_s[26][MAX_LEN_A];
char s2_s[26][MAX_LEN_B];
for(char ch = 'a'; ch <= 'z'; ch++) {
sprintf(s1_s[ch - 'a'], "%c%d%s", ch, s1_n[ch - 'a'], t_stringer1[ch - 'l']);
sprintf(s2_s[ch - 'a'], "%c%d%s", ch, s2_n[ch - 'a'], fs_stringer1[ch - 'o')]);
}
char* string_mix[MAX_NO_OF_STRINGS];
int k = 0;
for(int i = 0; i < 26; i++){
if(s1_s[i][3] - '0' != 0){
string_mix[k] = s1_s[i];
k++;
}
else if(s2_s[i][3] - '0' != 0){
string_mix[k] = s2_s[i];
k++;
}
}
The call to qsort is incorrect. The third parameter should be the size of each element. A correct call could be:
qsort(string_mix, (size_t) (k - 1), sizeof *string_mix, compare_at3);
or, if you prefer, and assuming string_mix is an array of char*:
qsort(string_mix, (size_t) (k - 1), sizeof (char*), compare_at3);
string_mix is an array of pointers - each array element is a pointer. qsort() calls need to pass the size of the element. #Klas Lindbäck
void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *));
char* string_mix[MAX_NO_OF_STRINGS];
// qsort(string_mix, (size_t) (k - 1), sizeof(char), compare_at3);
// I suppose k-1 represents the count of elements used
size_t number_of_elements = k - 1;
qsort(string_mix, number_of_elements, sizeof string_mix[0], compare_at3);
what am I doing wrong to get SIGSEGV segfault errors?
Wrong type assumed in compare function.
The compare function receives 2 pointers. Each is a pointer to an element of the array. In OP's case this is a pointer to a pointer.
int compare_at3(const void* a, const void* b){
static int k = 1;
printf("In compare_at3 %d iter\n", k++);
// const char *ia = a;
const char **ia = (const char **) a;
const char **ib = (const char **) b;
const char *sa = *ia;
const char *sb = *ib;
// Code could insure sa, sb are long enough
if (sa[0] == '\0' || sa[1] == '\0' || sa[2] == '\0') Handle_OddCase();
if (sb[0] == '\0' || sb[1] == '\0' || sb[2] == '\0') Handle_OddCase();
// The classic compare indium is below, it never overflows.
return (sa[3] > sb[3]) - (sa[3] < sb[3]);
}
Note: Concerning OP comment "It's a 2D array of those strings in the question defined like". string_mix is better described as a 1D array of pointers.
char* string_mix[MAX_NO_OF_STRINGS];
You convert a void pointer to a char pointer and access index 3 without knowing anything about the memory, the char pointer is pointing to inside the function. This is bad style and most probably the reason for your SIGSEGV, because you cannot access ia[3].
Furthermore, you say, you want to sort according to the 3rd letter... this would be ia[2], if ia were the correct pointer to the char array.
Please post your code... how did you create the array of char*?

comparing if void * contains 0 numbytes?

I need generic way to check if void * contains 0 till num_bytes.
I came up with following approach. *p does not contain same type of data everytime hence cant do *(type*)p
bool is_pointer_0(void *p, int num) {
void *cmp;
cmp = (void*)malloc(num);
memset(cmp, 0, num);
if (memcmp(p, cmp, num)) {
free(cmp);
return false;
} else {
free(cmp);
return true;
}
}
The function allocates & frees up num bytes on every call, not pretty I think.
Please suggest faster approaches. Appreciate the help.
Update :
How about this approach ?
bool is_pointer_0(void *p, int num) {
void *a = NULL;
memcpy(&a, p, num);
return a == NULL;
}
This code casts the void pointer to a char pointer. This allows the memory pointed at to be treated as a sequence of bytes. Then cycles through the specified length looking for non zero bytes. I do not know if the standards guarantee that this would work (ie casting a void* to a char* will provide a pointer to the raw bytes), but in real life it works
bool is_pointer_0(void *p, int num) {
char *c = (char *)p;
for(int i = 0; i < num; i++)
if(c[i]) return false;
return true;
}
You can cast the pointer to a char* or unsigned char* and check the values of the elements.
unsigned char* cp = reinterpret_cast<unsigned char*>(p);
for (int i = 0; i < num; ++i )
{
if ( cp[i] != 0 )
{
return false;
}
}
return true;
Note: this approach may be better for long buffers well aligned. Yet this answer is fast due to simplicity.
Since the memory, if all zeros, must compare to itself, use memcmp(): a platform specific optimized function.
int memcmp0(const void *buf, size_t n) {
#define TESTVALUE 0
const char *cbuf = (const char *) buf;
while (n > 0) {
// If odd size, last byte not 0?
if (n % 2 && (cbuf[n - 1] != TESTVALUE)) return 0;
// 1st half matches 2nd half?
size_t half = n / 2;
if(memcmp(cbuf, &cbuf[half], half) != 0) return 0;
n = half;
}
return 1;
}
This is easy to extend to other values other than 0 by changing TESTVALUE.
Note: at most log2(n) iterations.
Another after accept answer:
Since the memory, if all zeros, must compare to itself, use memcmp(): a platform specific optimized function.
Check the first value and then use memcmp() to compare ptr[0],ptr[1], then ptr[1],ptr[2], then ptr[2],ptr[3], etc.
int memcmpfast(const void *ptr, size_t n, char testvalue) {
const char *cptr = (const char *) ptr;
if (n == 0) return 1;
if (cptr[0] != testvalue) return 0;
return memcmp(cptr, cptr + 1, n - 1) == 0;
}
I'd probably go with something like this:
bool is_pointer_0(void* p, int num)
{
return std::search_n((char*)p, (char*)p + num, num, 0) == p;
}
Or this:
bool is_pointer_0(void* p, int num)
{
return std::all_of((char*)p, (char*)p + num, [](char c){return c == 0;});
}

C pass array to a function by pointer

I am new to C and pointers and I'd like know if its possible to pass an array pointer to a function instead of passing the array of characters itself. I am posting the snippet from the code.
char ipAddress[24];
int i, j;
for (i = 12; i <= 13; i++)
{
for (j = 1; j <= 254; j++)
{
sprintf(ipAddress,"192.168.%d.%d",i,j);
runCommand(ipAddress);
}
}
// ...
int runCommand (char x[24])
{
// Do stuff.
}
Arrays are always passed by pointer in C, not passed by value (copyed)
So
int runCommand (char x[24]);
is close equivalent of
int runCommand (char *x);
Yes, it is possible to pass a pointer to an array to a function. No, it is probably not what you want.
int runCommand(char (*x)[24])
{
if ((*x)[0] == '\0') // Option 1
return -1;
if (x[0][0] == '\0') // Option 2: equivalent to option 1.
return -1;
...
}
void alternative(void)
{
char y[24] = "Samizdat";
printf("%d\n", runCommand(&y));
}
That says x is a pointer to an array of 24 characters. Be very careful, though. In general, you do not want to pass a pointer to an array; you just want to pass pointers around.
int runCommand(char x[24]) // Or: char *x
{
if (x[0] == '\0') // Option 1
return -1;
...
}
void alternative(void)
{
char y[24] = "Samizdat";
printf("%d\n", runCommand(y));
}

Resources