Find substring in a string - c

Here is my code to find substring entered by the user in the given string.
bool find_str(char *str, char const *substr) {
while(*str) {
if(*str++ == *substr) {
char const *a = substr;
while((*str++ == *++a)); /*empty*/
if(*a == '\0')
return true;
}
}
return false;
}
// If match found, then return true, else false
int main(void) {
printf("%d", find_str("ABCDEF", "CDE")); /* Return true in this case */
printf("%d", find_str("ABCDE", "CDE")); /* Return false in this case */
}
As explained in the comment, it returns true whenever it ends with an additional characters. If it is not, then it returns false. I think there is a problem in increment/decrement operator. But I could not find how?

This is because your code decides to stop on finding \0 only after performing the comparison
*str++ == *++a
This condition will be true even when the match happens at the end of the string on null terminators, so the while loop would happily proceed beyond the end of both strings past the null terminator, causing undefined behavior.
Changing the condition to exit when *a is zero should fix the problem:
while((*str++ == *++a) && (*a));

I analysed you piece of code a little bit and based on my analysis,
I think the problem is in here
while((*str++ == *++a)); /*empty*/
perhaps you would like to add another statement like below
while((*str++ == *++a) && ( *a != '\0' ) ) ; /*empty*/
I guess you are missing a null check, what if both pointer are pointing to NULL termination they will still go forward that's exactly whats happening
I was going through your piece of code and found quite a few interesting things
Lets say the memory allocated for CDE is at X
say again the memory allocated for ABCDEF is at X+4 (this was the case in my machine)
and say memory block allocated for ABCDE is at some X+Y or what ever
now when the function is called second time
both pointers a and str point to respective memory locations starting at X+2 where Character C satisfies the condition above, however the condition will still be true even if they reach to end i.e at X+3 and hence a will move forward and point to A which makes your program behave erroneously

Related

Is it a bug in str_replace?

I searched for a string replacement function and found this question
What is the function to replace string in C?
If I use the code from the answer, it works but it looks wrong and gives a warning:
/home/dac/osh/util.c: In function ‘str_replace’:
/home/dac/osh/util.c:867:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
for (count = 0; tmp = strstr(ins, rep); ++count) {
It looks like it's maybe a bug with = and == . Is it a bug or did I misunderstand? Should it be == instead?
No, it's not. In this case, the value of tmp is actually intended to be used as the condition.
The return value of strstr:
char * strstr(char * str1, const char * str2 );
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of str1.
To remove the warning, try this:
for (count = 0; (tmp = strstr(ins, rep)) != NULL; ++count) {
No, it's not a bug. As per the body of the loop:
for (count = 0; tmp = strstr(ins, rep); ++count) {
ins = tmp + len_rep;
}
it actually uses tmp for something. The continuation condition in that for statement will assign the result of strstr() to tmp then execute the body as long as it's non-zero (i.e., as long as it found the string). That's because strstr() returns NULL only if the string cannot be found.
I suspect this is just gcc being paranoid in that it realises the continuation condition (the middle bit) on a for statement usually tends to be a comparison and you may have accidentally used = rather then ==.
That's why the diagnostic states warning: suggest ... rather than error: what the heck? :-) If you want to get rid of the warning (which isn't a bad position to take), simply do what it suggests and surround the entire continuation condition with parentheses.
[ strstr reference ] states the return value for char * strstr (char *str1,const char *str2 ) is :
A pointer to the first occurrence in str1 of the entire sequence of
characters specified in str2, or a null pointer if the sequence is not
present in str1.
Now for a little more C terminology, when you do :
tmp = strstr(ins, rep)
the main intent of C is to evaluate the expression as a whole and C evaluates it to the return value of strstr(ins, rep) here. The side effect is assigning this return value to tmp. The error :
suggest parentheses around assignment used as truth value
is a way gcc helps you to avoid a careless mistake, say typing a=b instead of a==b, I believe. Note that in the first case the value of b is used as truth value, but in the second case the result of is a equal b is used a truth value. By putting a () around tmp = strstr(ins, rep) you give the compiler the green signal to evaluate the value of the expression as truth value.
Side Note :
Putting () around tmp = strstr(ins, rep) makes it a full expression, and full expression is considered as a sequence point. A sequence point is a point in program execution at which all side effects are evaluated before going on to the next step.

Passing an array through "isalpha" through a loop

I've been at this for quite some time now and the existing answers offer little to no help. I am new to programming and am trying to write a sub-part of my program which tries to check whether any given input is constituted solely of alphabets.
For this, the idea I have in mind is to pass an entire array through the isalpha function by using a loop which passes each character at a time. The idea makes logical sense but I am having syntactic trouble implementing it. I will greatly appreciate any help!
Below is my code-
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(**<what I'm putting here is creating the problem, I think>**) = true)
{
printf("%c", p[i]);
}
}
You should modify your code as this (assuming you have the string type defined yourself):
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(p[i]) == true) // HERE IS THE ERROR, YOU HAD =, NOT ==
{
printf("%c", p[i]);
}
}
Operator = is for assignment and operator == is for comparison!
So what was happening? The assignment resulted in true, no matter what p[i] was.
As Quentin mentioned:
if(isalpha(p[i]) == true)
could be more elegant and error prune if written like this:
if(isalpha(p[i]))
Here is an example in C:
/* isalpha example */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i = 0;
char str[] = "C++";
while (str[i]) // strings in C are ended with a null terminator. When we meet
// the null terminator, while's condition will get false.
{
if (isalpha(str[i])) // check every character of str
printf ("character %c is alphabetic\n",str[i]);
else
printf ("character %c is not alphabetic\n",str[i]);
i++;
}
return 0;
}
Source
Ref of isalpha().
C does not have a string type.
Tip: Next time post your code as it is!
Aslo, as Alter noticed, it would be nice to use:
isalpha((unsigned char)str[i])
and in your code
isalpha((unsigned char)p[i])
for safety reasons.
Your example is here.
I.e. parameter of isalpha() is i-th character of string p. The only question is how to access to i-th character. Usually you can use []. I.e. just use following code: isalpha(p[i]) (I see that you already use [] in call of printf).
Also isalpha(p[i]) = true is wrong condition. It looks like you planned to check isalpha(p[i]) == true (you can skip == true).
Late but:
both other answers say omitting == true is desirable, but don't say it is necessary for portability.
The C core-language operators == != < <= > >= && || which return a 'logical' value use an int value of 1 for true and 0 for false. In C99 and up with stdbool.h and by common convention before that true is 1 and false is 0, so e.g. if( (a < b) == true ) will work correctly, although it is redundant and many (including me) consider it poor style. Language elements that test a logical value, namely if(c) while(c) for(;c;) and the operands to && || and the left operand to ?: consider any value that compares equal to 0 to be false, and any other value to be true.
The character-classification routines in ctype.h as well as some other standard-library routines like feof(f) and ferror(f) are specified to return some nonzero int for true and 0 (an int) for false, and on many implementations the nonzero value used for true is not (always) 1. In those cases isalpha(whatever) == true might result in testing say 4 == 1 and fail even when whatever is an alphabetic character. OTOH isalpha(...) != false or isalpha(...) != 0 does work correctly if you really want to write something explicit.

What does this for statement do?

I'm working on hash table codes on C language from my lecturer. There are 2 for that I've never seen before:
for(;t!=NULL;t=t->next)
and
for(;*s;s++)
well it's not like an ordinary for I've known before:
for(value first; value last; value ++ / --)
please kindly provide working example of those for.
for(;t!=NULL;t=t->next)
This loop means you have decleared and initialised t somewhere, so you don't need to initialise again.
for(;*s;s++)
This loop exactly does the same except the terminating condition. The value of *s should be zero for the loop to terminate.
Actually the syntax of for loop is:
for(initialization;boolean_condition;updation)
Any field can be left empty and if the boolean condition is false in some step the loop terminates.
For loop is
for(INIT; COND; AFTERTHOUGHT) {
CODE
}
INIT block runs only once at start of the loop
COND block runs after each iteration and check one need to continue this loop or not
AFTERTHOUGHT blocks runs after each iteration to update some values like counters
In your case
for(;t!=NULL;t=t->next)
There is no INIT block. Seems like it was done before this loop like
Node *t = pointerToRootNode;
for(; t!=NULL; t=t->next) {
// deal with t->data i guess
}
In second case
for(;*s;s++)
Also there is no INIT block. In COND block just dereferencing s pointer. Look at this example.
const char* some_str = "ab";
char* s = some_str;
if (*s) {
puts("It will be printed")
s++;
}
if (*s) {
puts("It will be printed too");
s++;
}
if (*s) {
puts("It will never be printed because *s == 0 i.e end of string");
}
for(;t!=NULL;t=t->next) or for(;*s;s++)
=> the initial condition is not required (assuming t is declared somewhere else)
for(int i = 10; i > 0 ; i --)
=> int i = 0; for (; i > 0; i--)
The first one iterates through a linked list until it reaches the very end, which is the place you could add the next node.
The second one does a similar concept, except it's looking for a value of zero when it dereferences the pointer.

what's wrong with my clean function?

I want to write a function clearing any string from numbers and signs like !##$%^&*()_+ but always I get this error: * glibc detected ./clear: invalid fastbin entry (free): 0x0000000001d29490 **
Here's the code:
void clean(char *dirty)
{
int i = 0, j = 0;
char *temp;
temp = strdup(dirty);
while(i < strlen(temp))
{
if(isalpha(temp[i]) && isspace(temp[i]))
{
dirty[j] = temp[i];
j++;
}
i++;
}
dirty[j] = '\0';
free(temp);
}
You should check for the return value of strdup. If the memory allocation encountered problems (e.g. not enough memory), temp gets the value NULL. Check if that is the case and exit with an error message.
Your if statement is always false:
if(isalpha(temp[i]) && isspace(temp[i]))
How could temp[i] be both alphanumerical and space?
Note also (although it's not the question) that this is rather a job for for than while (looping through all elements of an array until its end). It's always good to use the expected idiom.
This could also be done in place (no need for a temp string):
dirty[j] = dirty[i];
since i is greater or equal to j.
There could be several reasons causing the OP's code to crash:
1 strdup() returned NULL.
Test its result:
char * temp = strdup();
if (NULL == temp)
{
perror("strdup()" failed");
return;
}
2 On a 64bit system: strdup()'s prototype is missing
Include the appropriate header and, as it's not a standrd C, function make sure it is defined in there:
#define _POSIX_C_SOURCE 200809L /* or greater */ /* for gcc us option -std=c99 */
#include <string.h>
As per lulyon's comment: For various other possibe #define enabling strdup() protoyping please read here.
3 The string passed to clean(char * dirty) is NULL
Perform input validation:
if (NULL == dirty)
{
perror("invalid input");
return;
}
4 The string passed to clean(char * dirty) referrs to an unmutable constant
Do not call clean
like this:
char * dirty = "*ç%&/*alk 42";
clean(dirty);
neither like this:
clean("*ç%&/*alk 42");
nor like this:
#define dirty "*ç%&/*alk 42"
clean(dirty);
5 (As per Mike Hartl's comment) The string passed to clean(char * dirty) is missing its 0-termination
Undetectable from inside clean(), so fix the input.
if(isalpha(temp[i]) && isspace(temp[i])) // logic AND. The character could not be both alpha and space
should be
if(isalpha(temp[i]) || isspace(temp[i])) // logic OR.
The remaining part of code is of no problem.
Update:
The code works fine on my Window PC. So here I can only recommend checking errno to find what is wrong.
One more thing, check the pointer char *dirty and char *temp if they are empty before using them.
Update:
a useful link that explains strdup: Strdup returning address out of bounds
The logic of your loop seems to be flawed. This will never hold
isalpha(temp[i]) && isspace(temp[i])
so j will always be 0 at the end.
If you work under linux, You may consider valgrind usage for memory problems detection

Evaluating a postfix Expression in C

I'm trying to write a program that evaluates a postfix arithmetic expression. The program sends a character string to my function evaluatePostfix, which proceeds to identify operands and operators and come up with an integer solution. I am manipulating stacks in this program by pushing the scanned character as it is identified and of course doing the appropriate pop functions when needing to evaluate. Right now though, I'm having a problem with the program hanging in what appears to be an infinite loop. I guess I'm not really sure how to tell the function to proceed to the next character in the string after it has evaluated the first character. Another thing to note is that the user puts a space in-between each operand and operator. Here is my function:
int evaluatePostfix(char *postfixStr)
{
stack * s;
int x, y;
stackInit(&s);
do {
if(isOperand(postfixStr) == 1) {
stackPush(&s, postfixStr);
}
if(isOperator(postfixStr) == 1) {
y = atoi(stackPop(s));
x = atoi(stackPop(s));
char *str = malloc(10 * sizeof(char));
sprintf(str, "%d", applyOperator(x, y, postfixStr));
stackPush(&s, str);
}
} while (postfixStr != NULL);
return stackPop(s);
}
I know the functions that manipulate the stack are correct as they were provided by my instructor. Could someone perhaps give me a clue as to what I'm missing?
You could change the while condition to while (++postfixStr != NULL) to increment the pointer to the next character in postfixStr.
This increment is done using the prefix notation (++var vs var++) so that the next character is compared to NULL. I'm not familiar with the behavior of the stack functions you're using, but I would recommend changing the do { ... } while (++postfixStr != NULL); loop to a while (postfixStr != NULL) { ... } loop, and increment postfixStr at the end of that while loop's block.
The safest thing to do is add a string length parameter to your function:
int evaluatePostfix(char *postfixStr, int strLength)
You would then use a loop that explicitly steps from the beginning of the string at index 0 to index strLength - 1, which would safely handle empty and non-NULL-terminated strings.

Resources