I have a binary search function I am passing a pointer character array, the length of that array, a search pointer character array and another counter for something else.
int binarySearch(char* charArray, int len, char* searchItem, int counter)
{
int position;
int begin = 0;
int end = len-1;
int cond =0;
while(begin <= end)
{
position = (begin + end)/2;
// searchItem is a pointer array and the value I want to compare to is
// at the index of counter (determined outside of this function)
if((cond = strcmp(&charArray[position], &searchItem[counter])) == 0)
{
return position;
}
else if(cond < 0){
begin = position + 1;
}
else
end = position - 1;
}
return -1;
}
From here, going through the code by hand seems to make me want to think it should work fine, however it doesn't. I think I'm getting thrown off somewhere along the lines of my pointers and how I'm referring to them so the wrong data is being compared.
I've looked at it for too long now... really need some help here.
It is not very clear what is being searched in what. But I'm guessing that you are searching for a character in a sorted character array. If that is the case, you can't use a strcmp. Instead you can do:
if(cond = (charArray[position] - *searchItem) == 0)
strcmp assumes that the strings being compared are zero-terminated, and exactly equal length. Therefore, strlen(&charArray[position]) has to equal strlen(&searchItem[counter]). That means position == strlen(&charArray[0]) - strlen(&searchItem[counter]). You don't need to search at all. Either the suffix of charArray matches or it doesn't.
But that's probably not what you intended. What are you trying to achieve?
Are the strings to be compared all of the exact same length? Your code is assuming so. If not, you'll want to use strncmp( ), not strcmp().
strcmp compares all the characters in a char* up to the trailing '\0' character. So you cannot compare single characters (basically you always need two, the character and the trailing '\0') and you cannot compare parts of a string unless you insert a '\0' at the location up to which you want to perform the comparison.
Just for clarity, properly zero terminated strings (last character is '\0') are important for strcmp. strcmp compares two character arrays from the start up to the '\0' character and returns an appropriate comparison value (<0, =0, >0). And of course, both character arrays have to be the same length.
If these are ASCII strings and should be sorted in alphabetic order, I believe it should be
else if(cond < 0){
end = position - 1;
}
else
begin = position + 1;
}
I'm not certain how you wish to sort them though?
Related
I want to write a function that converts CamelCase to snake_case without using tolower.
Example: helloWorld -> hello_world
This is what I have so far, but the output is wrong because I overwrite a character in the string here: string[i-1] = '_';.
I get hell_world. I don't know how to get it to work.
void snake_case(char *string)
{
int i = strlen(string);
while (i != 0)
{
if (string[i] >= 65 && string[i] <= 90)
{
string[i] = string[i] + 32;
string[i-1] = '_';
}
i--;
}
}
This conversion means, aside from converting a character from uppercase to lowercase, inserting a character into the string. This is one way to do it:
iterate from left to right,
if an uppercase character if found, use memmove to shift all characters from this position to the end the string one position to the right, and then assigning the current character the to-be-inserted value,
stop when the null-terminator (\0) has been reached, indicating the end of the string.
Iterating from right to left is also possible, but since the choice is arbitrary, going from left to right is more idiomatic.
A basic implementation may look like this:
#include <stdio.h>
#include <string.h>
void snake_case(char *string)
{
for ( ; *string != '\0'; ++string)
{
if (*string >= 65 && *string <= 90)
{
*string += 32;
memmove(string + 1U, string, strlen(string) + 1U);
*string = '_';
}
}
}
int main(void)
{
char string[64] = "helloWorldAbcDEFgHIj";
snake_case(string);
printf("%s\n", string);
}
Output: hello_world_abc_d_e_fg_h_ij
Note that:
The size of the string to move is the length of the string plus one, to also move the null-terminator (\0).
I am assuming the function isupper is off-limits as well.
The array needs to be large enough to hold the new string, otherwise memmove will perform invalid writes!
The latter is an issue that needs to be dealt with in a serious implementation. The general problem of "writing a result of unknown length" has several solutions. For this case, they may look like this:
First determine how long the resulting string will be, reallocating the array, and only then modifying the string. Requires two passes.
Every time an uppercase character is found, reallocate the string to its current size + 1. Requires only one pass, but frequent reallocations.
Same as 2, but whenever the array is too small, reallocate the array to twice its current size. Requires a single pass, and less frequent (but larger) reallocations. Finally reallocate the array to the length of the string it actually contains.
In this case, I consider option 1 to be the best. Doing two passes is an option if the string length is known, and the algorithm can be split into two distinct parts: find the new length, and modify the string. I can add it to the answer on request.
I have a very simple function to convert a 3 char string representing a bit string to a decimal number:
int bin3_to_dec(char *bin) {
int result;
result=0;
printf("string: %s\n", bin);
printf("c0: %c\n", bin[0]);
printf("c1: %c\n", bin[1]);
printf("c2: %c\n", bin[2]);
if ((strcmp(&bin[0], "1") == 0))
result += 4;
if ((strcmp(&bin[1], "1") == 0))
result += 2;
if ((strcmp(&bin[2], "1") == 0))
result += 1;
printf("result: %d\n", result);
return result;
}
When I run the program and feed this function the string 111 it should calculate 7. Instead it outputs this:
string: 111
c0: 1
c1: 1
c2: 1
result: 1
Why is it not calculating the correct value? Why is only the third condition successfully passing?
Your string bin equal "111" really consists of four chars - that is '1', '1', '1', '\0' where the 4th char has the value zero which terminates (i.e. ends) the string.
So &bin[0] is the string "111"
and &bin[1] is the string "11"
and &bin[2] is the string "1"
So what your code is actually doing is the same as:
if ((strcmp("111", "1") == 0))
result += 4;
if ((strcmp("11", "1") == 0))
result += 2;
if ((strcmp("1", "1") == 0))
result += 1;
Only the last compare results in true so resultbecomes 1
&bin[0] is actually a pointer to a character array starting from 0th index which is 111. So, your first comparison fails. Similarly for second. But in your third comparison, &bin[2] is a pointer to character array starting from 2nd index which is 1 and hence it add 1 to result. So to make your code work:
you can check if(bin[0] == '1') // Here you compare the character at bin[0] and it is equal to 1 and so here the condition gets fulfilled.
C does not detect the end of a string until it encounters a null (i.e. \0). When you pass "111" into your function, you are actually passing a pointer to a block of memory that looks like this: "111\0". Thus, when you pass the address of bin[0] into strcmp(), strcmp operates on the full string "111". When you pass the address of bin[1] into strcmp(), strcmp operates on the string "11". Only when you pass the address of bin[2] into strcmp() do you get the behavior you were expecting, because in that case the next character in memory is a null.
if (bin[0] == '1') result += 4;
if (bin[1] == '1') result += 2;
if (bin[2] == '1') result += 1;
please note that &bin[0] is the same as bin
bin[0] is the first element
&bin[0] is a pointer to the first element just like bin
Have you tried printing &bin[1] (for example) as a string, instead of the individual characters? Because that's how strcmp() is going to see them.
In you do that, strcmp(&bin[0], "1") is clearly always non-zero, because &bin[0] is the full input string and (in our example) "111" is not at all like "1". Strings run until the null-terminator character.
You can use direct character comparisons (bin[0] == '1'), copy the character to a null-terminated string of its own, or (destructively) work from right to left and insert the null character ('\0') after the character that interests you. But you can't compare the middle of a string as a single character.
As mentioned by others, you are confusing those strings. The three of them are strings, however, string in java is an array of chars. So when you mean the string "1" using &bin[0], you are actually comparing "111". Why? Pointer to an array of chars make a string with the chars in this array starting where your pointer shows and continues to the end.
So when you point at the first letter you get "111", when you point at the second letter you get "11" and when you point at the last character you get "1", thats why your sum is 1. You can try to pass as argument the string "1111", you can see that your result is 0 intead of 1.
Your code seems somehow baffled around a function call of strcmp(), which isn't needed and would consistently return non-zero for any comparison between the string literal "1" and any "sub-string" pointed to in your code (&bin[0], &bin[1]), except for the one-printable-member-string &bin[2], if also "1". Let's have a walk-through.
As you have properly written in your function prototype, the pointer to the first element of the character array is being passed by value to your called function and copied as its argument. This is the "mechanism" for the part of memory populated by the array pointed to, to become visible by the called function, if its "upper bound" is known.
There are two means of having its upper bound known:
Passing the char array size as additional argument to the function, or
Null-terminating the char array in the calling function, so the called function can interpret it as string, which is your choice. The called function can either use strlen() to determine string length (size), or step through it, incrementing the counter, until a null-character is reached, and read size from the counter.
If the calling function already receives the array as a null-terminated string of '0' and '1' characters, the second looks more practical.
Allowing for up to as many characters as allowed by the storage capacity of the return data type of the called function (in this case int) clarifies the problem and simplifies the code. The caller function should guard against overflow.
The called function should only compare every array member's ASCII value with '1' and convert if equal.
For this strcmp isn't needed.
Please see the comments in this demonstration code, based on your post:
#include <stdio.h>
#include <string.h>
#define BPB 8 //bits per byte
int bin_to_dec(char *bin) //called function
{
int result=0;
int l = (int)strlen(bin);
for (int i = 0; i < l; i++){
printf("c%d: %c\n", i, bin[i]);
if(bin[i] == '1') //compare value of the i-th element
result += 1<<(l - i - 1); //convert to power-of-two and add to the result
}
return result;
}
int main(int argc, char *argv[]) //calling function
{
size_t siz = BPB*sizeof (int); //size for each char to represent one bit
char s[siz + 1]; //characters, each representing one bit + terminating '\0'
if((argc < 2)||(argc > 2)) //fail-safe check for correct count of arguments
return 1;
size_t len = strlen(argv[1]) ; //get length of the input string
if ( len > siz ) //check against too long input which would cause overflow
return 2;
strncpy(s, argv[1], len);
s[len] = '\0'; //appending the terminating null-character
for(int i = 0; i < (int)len; i++)
if((s[i] < '0')||(s[i] > '1')) //fool-proof check against 'off-limit' input
return 3;
printf("decimal: %d\n", bin_to_dec(s));
return 0;
}
In one of my assignments, I was required to use linear search to find the last char of a string and set it to a pointer, it is just a simple string eg "blah blah blah". To do this I used
int length = strlen(string);
to find the length, then used a for loop
for (i=1;i<length;i++){
if (string[i]==0){;
end_pointer = &string[i-1];
}
Is there any difference between using linear search for 0 to set the pointer as opposed to using length:
end_pointer = &string[length-1];
I think what your professor is really looking for is:
int i = 0;
while( '\0' != string[i] ) i++;
for the search
Assign after the looping has completed for best efficiency:
char * end_pointer = &string[i - 1];
I think I need to explain how strings are stored in C.
Since strings can, in general, have arbitrary length, there needs to be a way to represent that length along with the content of the string. The two most trivial ways of representing the length are as follows.
explicitly keep track of length
use a special token to denote the end of string
The C language went with the second option. Specifically, '\0' is used to denote the end of the string. So if you have a char * p, then that is a pointer†that points to the first character; the second character in the string is p[1] == *(p+1), and so on.
So how do you get the length of the string? In the first method of representing strings (NOT the C way), it's already explicitly available. With C strings, you have to start at the beginning and count how many characters there are until the special token ('\0' in C). This is called a linear search for the end of string token.
strlen implements such a linear search, but it sounds like you are not supposed to use it. Regardless, strlen doesn't actually give you the pointer to the end of the string; you would have to compute it as
char *endPtr = string + strlen(string);
In this case, endPtr will actually point to the null-termination character, which is just past the end of the string. This is a common paradigm in C for specifying ranges: the start of the range (string in this case) is usually inclusive, and the end of the range (endPtr in this case) is usually exclusive.
â€
char * could just be a pointer to a single char and not necessarily a string, but that doesn't concern us here.
The difference between using a linear search for '\0' to set the pointer as opposed to using length derived from strlen() is a slight potential efficiency change.
If one rolls their own code or uses the standard library function strlen(), it is still the same order of complexity O(n). If anything, srtrlen() has potential of being more efficient.
If the goal is to create you own code and point to the last char in a string (not the '\0'), handle "" as a special case, otherwise perform a simple loop;
char *LastCharPointer(char *string) {
if (*string == '\0') {
return NULL;
}
do {
string++;
} while (*string);
return string - 1;
}
If the goal is to point to the null chanracter '\0':
char *NullCharPointer(char *string) {
while (*string) string++;
return string;
}
I am assuming the code you pasted above is not the actual code you wrote, it would be :
for( i = 0; i < strlen( string ); i++ ) {
if( string[ i ] ){
end_pointer = &string[i - 1];
}
}
You can do this in two ways :
char * end_pointer = &string[ strlen( string ) - 1 ]
or
for( i = 0; string[ i ] ; i++ );
char * end_pointer = &string[ i - 1 ]
Effectively when you call strlen( ), it runs in linear time to calculate the length. Once you have the length you can index into the string directly or, you could yourself search for the terminating '\0' character. All this works assuming that your string is null-terminated.
EDIT : The second option had a missing ";".
I have a bunch of strings that I need to verify if these have all spaces.
I can do strlen(trim(strct.data)) > 0.
But, it's not null terminated, but the length is known.
i.e. if strct.len is 5 then I need to verify if strct.data has spaces for 5 chars. 6th char is not guaranteed to be null. I have an array of strct each of which can have different length of data to be validated for spaces.
I tried strnlen(trim(strct.data)) and later realized it didn't fix anything as the trim already removed all spaces.
Any ideas other than the obvious looping over each character of strct.data (my last option if there is no other go)?
note: trim is a userdefined function I use to remove leading and trailing spaces. It doesn't stop until the NULL too. I am looking for a way to handle both.
How to ensure the string is full of spaces for a given length?
step 1:
char buf[MAX_SIZE];
sprintf(buf,"%*s",MAX_SIZE-1,""); //fill buffer with spaces
step 2:
Now use strncmp() compare strct.len number of character of strct.data character array with buf
if(strncmp(strct.data ,buf ,strct.len) ==0)
{
//all are spaces
}
You need not to repeat step1.
Another solution jxh suggested you can also use memset() instead of sprintf()
memset(buf, ' ', sizeof buf); //fill buf with all spaces
You need do this once, next time onwards you need not do this.
You can also use VLA.
declaring char buf[strct.len];
but you need to use memset each time.
Probably the best is doing the looping yourself:
for(int i=0; i<strct.len; ++i) {
if(strct[i] != ' ') {
return false;
}
}
return true;
As the character array is not null terminated, it is not a string.
But let's not quibble on that point and make a fast routine for large arrays.
IsCharArrayAllSpace(const char *p, size_t Length) {
if (Length < 1) return 1; // TBD: decide how to handle the zero-length case
return (p[0] == ' ') && (memcmp(p, &p[1], Length-1) == 0);
}
This is what I have so far:
for(i = 0; i <= 9; i++){
printf("%d", i);
found = strpbrk(nameholder[i], searchterm);
if(strpbrk(nameholder[i], searchterm) == searchterm){
printf("found\n");
foundwhere = i + 1;
break;
}
}// end for
When I run the program, the strpbrk function finds the string, but for some reason it never triggers the if statement. What am I missing?
According to http://en.cppreference.com/w/c/string/byte/strpbrk , strpbrk() is for
const char* strpbrk( const char* dest, const char* str );
Finds the first character in byte string pointed to by dest, that is also in byte string pointed to by str.
Thus, if you really want to find the whole searchterm instead of any character of searchterm in nameholder[i], you should use strcmp or strstr.
Also note that the operator == can not be used to compare the equality of two char* strings since it simply compare if the addresses are equal or not disregarding the string content. Use strcmp() instead.
If I correctly understood (your description is vague) what you are trying to do, then you seem to be using a wrong function.
Quoting cpp docs on strpbrk:
Returns a pointer to the first occurrence in str1 of any of the characters that are part of str2, or a null pointer if there are no matches.
That's not what you want it to do, right? You should be looking at strcpm function.
http://www.cplusplus.com/reference/clibrary/cstring/strcmp/
Your code should look like:
for(i = 0; i <= 9; i++){
if(strcmp(nameholder[i], searchterm) == 0){
printf("found\n");
foundwhere = i + 1;
break;
}
}// end for