I'm fairly new to C programming but trying my best to understand it. I have two dynamic strings that are populated from two plain text files. One being a form of a dictionary, and the other one just a user input. What I want to get is binary search each user input word in the dictionary and find out if it is present (sort of a spell checker I guess).
I'm stuck on my binary search function:
char **dictElem;
int dictSize;
char **inputElem;
int binsearch(const char *val){
int pos;
int beg=0;
int end=dictSize-1;
int cond=0;
while (beg<=end){
pos=(beg+end)/2; //Jump in the middle
if ((cond=strcmp(dictElem[pos],val)) == 0)
return pos;
else if (cond<0)
beg=pos+1;
else
end=pos-1;
}
return 0;
}
Both dictElem and inputElem were already read by other methods and (let's say) both [0] elements are equal strings "aa".
However after I run the binsearch(inputElem[0] it always returns 0. I tried just strcmp(dictElem[0],inputElem[0]) and it returns 1.
Where am I going wrong? Is it comparing char** and char*?
UPD:
Function that's loading the dictElem
void readd(FILE *file){
int i=0,size=0; /* local size */
char line[1024]; /* Local array for a single word read */
printf("Loadingn dict...\n");
while ((fgets(line,sizeof(line),file))!=NULL){
dictElem=(char**)realloc(dictElem,(size+1)*sizeof(char *));
dictElem[size++]=strdup(line);
}
printf("Total elements loaded: %d\n",size);
}
Function that reads a user file is very similar, just a little different format.
The problem with your code is in this line if ((cond=strcmp(dictElem[pos],val) == 0)). This line of code assigns the result of expression strcmp(dictElem[pos], val) == 0 to the variable cond, and then checks whether cond is zero or not.
I guess your original intent was to store in cond the result of strcmp, so you should move the closing parenthesis before ==. The correct line is if ((cond = strcmp(dictElem[pos], val) == 0).
There are some other problems with your code:
0 is used as special not-found value, but in the same time 0 can be
returned when element is found at index 0.
Using char *val, when
it is better to use const char *val, because contents of this
string aren't going to be modified. It is always better to write const-correct code.
Your problem is this line:
if ((cond=strcmp(dictElem[pos],val) == 0))
The parentheses are giving it the wrong order of evaluation and cond will always end up 0 or 1 (because you're assigning the results of the comparison strcmp() == 0 to it). Try this instead:
if ((cond=strcmp(dictElem[pos],val)) == 0)
Related
I am not a C developer or know much about C but I came across this C interview question:
int toto(char *a, char *b){
while(*a++ == *b++);
return(*a == 0 && *b == 0);
}
I spent a good amount of time trying to figure it out and after reading a few things online I kind of grasped what it is trying to do but there are still some weird behaviours that arise.
From what I understand (please correct me if I'm wrong), this piece of code will go through two strings (char arrays) and determine whether they are equal up until the last character and returns true only if the last character is different. return (*a == 0 && *b == 0) checks for the 0 integer that all strings end with in C. This only happens after the loop has exited i.e when two characters aren't equal before the increment happens; so if the last two characters are not equal, it will increment them to the 0 int and go through to the return statement. I also noticed that that if the strings differ by 1 then it still returns true if the strings are equal up until n-1 for example:
char a[] = "ggr"
char b[] = "ggre"
//returns 1
char a[] = "ggr"
char b[] = "ggf"
//returns 1
I found this behaviour peculiar but the test case that I can't understand is the following:
char a[] = "abcd";
char b[] = "abcd";
//returns 1
char a[] = "abc"
char b[] = "abc"
//returns 0
I understand why abc returns false but I have no idea why it wouldn't return the same for abcd. To me, it seems like it treats strings of different lengths differently but the code doesn't seem to care about the length.
Can anyone explain what the code intends to do and why the code behaves differently when given different lengths of strings. I have a feeling it has to do with the order of precedence for certain operators but I couldn't find an answer.
Edit: It seems the code supplied by the interview is buggy on purpose, I was under the impression that the code is valid.
Your code has undefined behavior. It will eventually access memory beyond the null terminated char array. This code is wrong in that sense.
The correct implementation would be something like
int toto(char *a, char *b){
while(*a && *b && *a == *b) a++,b++;
return (*a - *b)?0:1;
}
Because it has a bug. If the two strings are exactly equal until the end of either string, then you will iterate past the end of the string. You will then have undefined behaviour, meaning sometimes it can work, or sometimes it could crash (or do a plethora of other things). Consider adding this to your function:
int counter = 0;
while(*a++ == *b++) {
printf("Count %d\n", ++counter);
}
Live example.
You will note it could print:
Count 1
Count 2
Count 3
Count 4
Which means your return line (return(*a == 0 && *b == 0);) will be dereferencing past the end of the string (i.e. on the 5th string character).
I am doing a c program but the sample input is not giving the sample output if I use the. I think my program is not calling the function. I guess I have declared it incorrectly. Or my logic is wrong. What I am getting is a zero as output. The question is given below.
Write a C function to find the kth occurrence of an integer n in a sequence of non-negative integers, and then call your function from
main.
Your function should be according to the following declaration:
int find(int n, int k);
Input
You are given the input in two lines:
The first line contains a non-negative integer, say n, and a positive
integer k, in that order. You have to find the kth occurrence of n in
the sequence below.
The second line consists of a sequence of non-negative integers,
terminated with a -1. The -1 is not part of the sequence.
Output
If n occurs k times in the sequence, then output the index of the kth
occurrence of n in the sequence.
If n does not occur k times in the sequence, then output -1.
(For example, the second occurrence of the integer 3 in the sequence
1 1 3 2 3 -1 is at position 4 in the sequence. The first index in the
sequence is 0.)
Input:
3 2
1 1 2 3 3 -1
Output:
4
Code:
#include<stdio.h>
int check(int a,int n ,int k ){
int f;
int value;
int counter=0;
counter++;
if (a==n)
{
f++;
}
if(f==k)
{
value= counter;
}
return value;
}
int main(void)
{
int n , k,a;
int tempo;
scanf("%d",&n);
scanf("%d",&k);
while(a!=-1)
{
scanf("%d",&a);
tempo=check(a,n,k);
}
printf("%d",tempo);
return 0;
}
Your check function has numerous problems:
int check(int a,int n ,int k ){
Your prototype does not match the one in the assignment - you're only supposed to take 2 arguments, neither of which is the sequence of values you're checking against. Somehow, someway, you are supposed to access that sequence from within the body of the function, either by referencing a global array (bad), or by reading the input sequence from within the body of the function (slightly less bad, and probably the intent of the exercise1).
int f;
int value;
auto variables are not implicitly initialized in a declaration - their initial value is indeterminate (it may be 0, it may be a trap representation, it may be a valid non-zero integer value). This will cause problems later.
int counter=0;
counter++;
I think I know what you're trying to go for here, and it won't work as written2 - counter only exists for the lifetime of the function. Each time you call check, a new instance of counter is created and initialized to 0. It won't remember the value stored in it from a previous call.
if (a==n)
{
f++;
f isn't guaranteed to be 0 at this point (or any other specific value). It could be 0, or it could be any non-zero value, or even a trap representation (a bit pattern that does not correspond to a valid integer value).
}
if(f==k)
{
value= counter;
}
return value;
}
At this point, counter is only ever going to be 1 - you initialize it to 0 at function entry and immediately increment it, then you never touch it again. So value is only ever going to be indeterminate or 1.
So, how should you proceed from here and satisfy the requirements of the assignment?
The less bad option is to read the sequence from within the check (or find) function, although that's still pretty bad (again, I/O should be a separate operation, and we're assuming all input comes through stdin).
int find( int n, int k )
{
int next; // next value in the sequence
... // additional items for index, number of matches, etc.
while ( scanf( "%d", &next ) == 1 && next != -1 )
{
// update index, does next match n, is it the k'th match, etc.
}
...
}
scanf is a poor tool for interactive input, but at this point is the simpler approach.
Which, honestly, isn't any better than keeping a global array. I/O should be factored out from computation whenever possible, and if a function *is* required to read from an input stream, that stream should be specified as a parameter to the function - you shouldn't force your code to assume all input comes through stdin.
counter would need to be declared static for it to retain its value from call to call.
My solution is totally extension of what John Bode said above and as John Bode said, you are using more parameters than the preferred. You should stick to only 2 parameters. And as you have two parameters n(for search element) and K(k th occurrence) you cant pass an sequential array to that function, So you should start reading(scanning) the sequence inside the find().
As the program clearly says it terminates with -1. You can use this to end the loop in terminating the find function.
Scan function returns true as long as it reads. even for -1 it returns true so you should use the value!=-1. And inside the loop you can use your logic of matching and finding the index number.
int find(int n, int k){
int next;
int match=0;
int index=0; //for parsing the sequence
while( scanf("%d", &next) ==1 && next!=-1){
if(next == n){
match++;
if(match==k)
return index;
}
index++; //move the index
}
return -1;
}
I have a problem when I try to compare the content of two char arrays.
Sometimes
If the string is less than the actual size of the array, in it there is no sequence of '\0' but often there are unexpected characters (in the xcode debug there was the '\x01' character and in the control loop I use To check if a memory cell of the array was the same as the other, it was not the same). So to overcome this problem I decided to force the user to write the array content exactly as array size(-1): ex. array[3], the users write "hi" (without the ""). So I was wondering if there is a way to compare the two strings (I'm not talking about length but content) without fully filling the array in order to compare the content ofenter code here the two arrays through a simple cycle. (I was thinking of initializing the vector with \ 0 but I do not know if there can be problems)
thanks for the answers
this is an example of the code
}while(sent !=1);
for(contatore=0; contatore<MAXNOME; contatore++){
if(UserName[contatore] == persona.username[contatore]){
controlloUsr++;
}
}
for(contatore=0; contatore<MAXNOME; contatore++){
if(password[contatore] == persona.password[contatore]){
controlloPsw++;
}
}
if(controlloUsr == MAXNOME && controlloPsw == MAXPSW){
return 1;
} else {
return 0;
}
I'm not sure if that's what you're asking, but there is no way to browse an array of chars in C without giving the code a stop sequence, like a \0, or you will browse it forever (well, until a wild segfault appear...)
You can write your own strncmp function for this, something like :
int my_strncmp(char *str1, char *str2, size_t max, char c)
{
size_t n = 0;
while (n < max)
{
if ((str1[n] != str2[n]) || (str1[n] == c) || (str2[n] == c))
return 0;
n++;
}
return 1;
}
This will return 0 if your char c is met, or if the strings are different, or 1 if the string are the same until max char. Just be sure that one of the two conditions is met or you code will crash into a segfault / have undefined behavior, since you will browse out of your allowed memory range.
the function strcmp() and the strncmp() are made for this exact operation,.
You can read the man page for those two functions for all the details.
I'm looking for a way to check if a specific string exists in a large array of strings. The array is multi-dimensional: all_strings[strings][chars];. So essentially, this array is an array of character arrays. Each character array ends in '\0'
Given another array of characters, I need to check to see if those characters are already in all_strings, kind of similar to the python in keyword.
I'm not really sure how to go about this at all, I know that strcmp might help but I'm not sure how I could implement it.
As lurker suggested, the naive method is to simply loop on the array of strings calling strcmp. His string_in function is unfortunately broken due to a misunderstanding regarding sizeof(string_list), and should probably look like this:
#include <string.h>
int string_in(char *needle, char **haystack, size_t haystack_size) {
for (size_t x = 0; x < haystack_size; x++) {
if (strcmp(needle, haystack[x]) == 0) {
return 1;
}
}
return 0;
}
This is fairly inefficient, however. It'll do if you're only going to use it once in a while, particularly on a small collection of strings, but if you're looking for an efficient way to perform the search again and again, changing the search query for each search, the two options I would consider are:
If all_strings is relatively static, you could sort your array like so: qsort(all_strings, strings, chars, strcmp);... Then when you want to determine whether a word is present, you can use bsearch to execute a binary search like so: char *result = bsearch(search_query, all_strings, strings, chars, strcmp);. Note that when all_strings changes, you'll need to sort it again.
If all_strings changes too often, you'll probably benefit from using some other data structure such as a trie or a hash table.
Use a for loop. C doesn't have a built-in like Python's in:
int i;
for ( i = 0; i < NUM_STRINGS; i++ )
if ( strcmp(all_strings[i], my_other_string) == 0 )
break;
// Here, i is the index of the matched string in all_strings.
// If i == NUM_STRINGS, then the string wasn't found
If you want it to act like Python's in, you could make it a function:
// Assumes C99
#include <string.h>
#include <stdbool.h>
bool string_in(char *my_str, char *string_list[], size_t num_strings)
{
for ( int i = 0; i < num_strings; i++ )
if (strcmp(my_str, string_list[i]) == 0 )
return true;
return false;
}
You could simply check if a string exists in an array of strings. A better solution might be to actually return the string:
/*
* haystack: The array of strings to search.
* needle: The string to find.
* max: The number of strings to search in "haystack".
*/
char *
string_find(char **haystack, char *needle, size_t max)
{
char **end = haystack + max;
for (; haystack != end; ++haystack)
if (strcmp(*haystack, needle) == 0)
return *haystack;
return NULL;
}
If you're wanting the behavior of a set, where all strings in the array are unique, then you can use it that way:
typedef struct set_strings {
char **s_arr;
size_t count;
size_t max;
} StringSet;
.
.
.
int
StringSet_add(StringSet *set, const char *str)
{
// If string exists already, the add operation is "successful".
if (string_find(set->s_arr, str, set->count))
return 1;
// Add string to set and return success if possible.
/*
* Code to add string to StringSet would go here.
*/
return 1;
}
If you want to actually do something with the string, you can use it that way too:
/*
* Reverse the characters of a string.
*
* str: The string to reverse.
* n: The number of characters to reverse.
*/
void
reverse_str(char *str, size_t n)
{
char c;
char *end;
for (end = str + n; str < --end; ++str) {
c = *str;
*str = *end;
*end = c;
}
}
.
.
.
char *found = string_find(words, word, word_count);
if (found)
reverse_str(found, strlen(found));
As a general-purpose algorithm, this is reasonably useful and even can be applied to other data types as necessary (some re-working would be required of course). As pointed out by undefined behaviour's answer, it won't be fast on large amounts of strings, but it is good enough for something simple and small.
If you need something faster, the recommendations given in that answer are good. If you're coding something yourself, and you're able to keep things sorted, it's a great idea to do that. This allows you to use a much better search algorithm than a linear search. The standard bsearch is great, but if you want something suitable for fast insertion, you'd probably want a search routine that would provide you with the position to insert a new item to avoid searching for the position after bsearch returns NULL. In other words, why search twice when you can search once and accomplish the same thing?
I'm trying to find the size of the longest word in an array of structs.
I have this array of structs:
struct Vocabolo{
char parola[20];
char *sinonimi[5];
char definizione[300];
};
typedef Vocabolo vocabolo;
vocabolo parole[30];
Now I have to use incremental recursion in order to find the size of the lognest word in the array. Words are contained each in:
parole[n].parola
I'm using this code:
int Lunghezza_parola(vocabolo *parole,int n){
int y;
if(n == 1)
return strlen(parole[0].parola);
else {
y = strlen(parole[n-1].parola);
return Scegli_max(y,Lunghezza_parola(&parole,n-1));
}
}
Wnere Scegli_max is:
int Scegli_max(int y, int lunghezzaStringa){
if (y >= lunghezzaStringa)
return y;
else
return lunghezzaStringa;
}
In this program the user has to insert words manually and each time a word is inserted, the program should put them in alphabetical order.
If I try to input something like "come" as parole[0].parola and "hi" parole[1].parola and start this function the result is 3. Also it seems to works only if the longest word is in the last position of the array.
Any idea?
PS: this is part of a longer programm so is impossible to write here all the code but i'm quite sure everithing works fine exept this function so the words are ordered correctly in the array of struct.
Your problem is return Scegli_max(y,Lunghezza_parola(&parole,n-1));
You call Lunghezza_parola giving it &parole which is already a vocabolo *parole so this becomes a vocabolo **parole and the pointer is now invalid.
Try changing your return to return Scegli_max(y,Lunghezza_parola(parole,n-1));
Your problem is the line return Scegli_max(y,Lunghezza_parola(&parole,n-1)); . remove the &.
You should pass the value of the pointer, not a pointer to it.