C: Problem in comparing two strings in a function - c

Good morning everyone, I have to simulate the operation of the strstr() function with a function written by me.
In the code I slide the original string in a temporary string and then the comparison with the string to look for, if they are equal it should return 1.
But even if the strings are equal and of the same length the code never enters the if cycle and therefore never returns 1.
My code:
int *strstr_new(char *s7, char *s8) {
int length_s7 = strlen(s7);
int length_s8 = strlen(s8);
char search_string[length_s8];
printf("%d\n", length_s8);
for(int i=0; i<length_s7; i++) {
for(int j=0; j<length_s8; j++) {
search_string[j] = s7[i+j];
search_string[j+1] = '\0';
}
printf("%s\n", s8);
printf("%s\n", search_string);
printf("%d\n", length_s8);
printf("%d\n", strlen(search_string));
//search_string[length_s8+1] = '\0';
if(search_string == s8) {
return(1);
}
}
if(search_string != s8) {
return(NULL);
}}
Does someone have an idea of where I'm wrong?
Thanks!

The function declaration
int *strstr_new(char *s7, char *s8);
looks very strange.
For example why is the return type int *?
Why are function parameters named s7 and s8 instead of for example s1 and s2?
Why are not the function parameters qualified with const?
Creating a variable length array within the function is inefficient and redundant and can lead to stack exhaustion.
char search_string[length_s8];
This loops
for(int j=0; j<length_s8; j++) {
search_string[j] = s7[i+j];
search_string[j+1] = '\0';
}
invokes undefined behavior because this statement
search_string[j+1] = '\0';
writes beyond the array when j is equal to length_s8 - 1.
In this statement
if(search_string == s8) {
there are compared two pointers and it is evident that they are unequal because they point to different arrays.
Without using standard C functions except the function strlen (that could be also defined explicitly) the function can be declared and defined the following way
#include <stdio.h>
#include <string.h>
char * strstr_new( const char *s1, const char *s2 )
{
char *p = NULL;
size_t n1 = strlen( s1 );
size_t n2 = strlen( s2 );
if ( !( n1 < n2 ) )
{
for ( size_t i = 0, n = n1 - n2 + 1; p == NULL && i < n; i++ )
{
size_t j = 0;
while ( j < n2 && s1[i + j] == s2[j] ) ++j;
if ( j == n2 ) p = ( char * )( s1 + i );
}
}
return p;
}
int main( void )
{
const char *s1 = "strstr_new";
const char *s2 = "str";
for ( const char *p = s1; ( p = strstr_new( p, s2 ) ) != NULL; ++p )
{
puts( p );
}
}
The program output is
strstr_new
str_new
If you are allowed to use standard string functions along with strlen then the loop within the function strstr_new can be simplified the following way
for ( size_t i = 0, n = n1 - n2 + 1; p == NULL && i < n; i++ )
{
if ( memcmp( s1 + i, s2, n2 ) == 0 ) p = ( char * )( s1 + i );
}

The biggest problem in your code is comparing strings with == operator. Both search_string and s8 are char pointers, which means you're comparing addresses of different variables, obviously to return False. Try adding another for loop to compare each char in search_string to the corresponding char in s8 (using the dereferencing operator *).

Your string comparisons won't work because you are comparing the addresses of those strings instead of the strings themselves, you'd what to use something like strcmp or memcmp to compare two strings.
Your return type is also not compatible with the return you have particularly if the strings match. I'd return 1 if the string is found and 0 if it's not, for that you'd need to change the return type to int only.
The second string comparison is unneeded, you already test the existance of the substring inside the loop so you just need to return 0 if the loop finds it's way to the end.
Lastly the temporary string is too short and will allow for access outside its bounds, inside the loop.
e.g. if length_s8 is 4 will write to
search_string[4], 5th index, out the bounds of the array.
int strstr_new(char *s7, char *s8) //return 1 for found, 0 for not found
{
int length_s7 = strlen(s7);
int length_s8 = strlen(s8);
char search_string[length_s8 + 1];//you'd want to avoid buffer overflow
for (int i = 0; i < length_s7; i++)
{
for (int j = 0; j < length_s8; j++)
{
search_string[j] = s7[i + j];
search_string[j + 1] = '\0';
}
if (!strcmp(search_string, s8))
{
return 1; //if the string is found return 1 immediately
}
}
return 0; //if it reaches this point, no match was found
}
A couple of tests:
printf("%d\n", strstr_new("this is my string", "this i"));
printf("%d\n", strstr_new("this is my string", "ringo"));
printf("%d\n", strstr_new("this is my string", "ring"));
printf("%d\n", strstr_new("this is my strin", "ths"));
Output:
1
0
1
0

Related

Replacing a sequence of ascending characters by ascii code with a specific pattern

I am doing some kind of challenge in C in the internet and got the following mission:
Given a string, that consists of some ascending characters one after the other (by ASCII value), return the same string, but replace the middle letters of the sequence with one minus sign
Example:
Given the following input: dabcefLMNOpQrstuv567zyx
We expect the following output: da-cefL-OpQr-v567zyx
The code I've tried:
/* Importing useful libs */
#include <stdio.h>
#include <string.h>
/* Declaring boolean definitions */
typedef enum {
false,
true
}
bool_enum;
/* Declaring Max. Input Length */
#define MAX_INPUT_LENGTH 80
void sequence_replace(char string[]);
/* Main Function */
int main() {
char input_str[MAX_INPUT_LENGTH];
printf("Please enter the string you'd like to switch its sequences with the three char method: ");
scanf("%s", input_str);
sequence_replace(input_str);
return 0;
}
void sequence_replace(char string[]) {
int first_char, last_char;
int slen = strlen(string);
bool_enum sequence = false;
for(int i = 0; i < slen; i ++) {
int s1 = string[i];
int s2 = string[i+1];
if (s1 + 1 == s2) {
if (sequence = false) {
sequence = true;
first_char = i;
}
}
if (s1 + 1 != s2) {
if (sequence = true) {
last_char = i;
string[first_char + 1] = '-';
for(int j = first_char+2; j < last_char; j++) {
string[j] = '';
}
}
sequence = false;
}
}
printf("Sequences after replacement are: %s", string);
}
Basically what I tried to do, is in the sequence_replace function iterate over the string until I find one character whose ascii code + 1 equals to the ascii code of the next character, I change a boolean flag to true to show that I am inside a sequence as well as keeping the index of when the first character of the sequence showed up, then once it hits a character whose ascii code - 1 is not equal to the previous character ascii code, I then switch the character that comes next after the first character with '-' sign and then just run a loop until the end of the sequence to replace all other remaining chars with just an empty string.
Unfortunately, doesn't seem to be working, Would like to get any help if possible.
For starters there is no need to introduce this typedef declaration
/* Declaring boolean definitions */
typedef enum {
false,
true
}
bool_enum;
It is much better just to include the header <stdbool.h> and use names bool, false and true defined in the header.
The function itself should be declared like
char * sequence_replace(char string[]);
Using the function strlen is redundant and inefficient.
As it follows from the provided example you should check whether a current character is an alpha character or not.
You may not declare integer character constants that do not contain a symbol like this
string[j] = '';
That is in C there are no empty integer character constants.
Also there is a logical error in this if statement (apart from the typo in the inner of statement if (sequence = true) { where there is used the assignment operator = instead of the equality operator ==)
if (s1 + 1 != s2) {
if (sequence = true) {
last_char = i;
string[first_char + 1] = '-';
for(int j = first_char+2; j < last_char; j++) {
string[j] = '';
}
}
sequence = false;
}
It unconditionally write the symbol '-' even if there are only two characters that satisfy the condition
s1 + 1 == s2
In this case according to the provided example the symbol '-' is not inserted.
Also for example the for loop will not process the tail of the string that represents an increased sequence of letters.
The function can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <ctype.h>
char * sequence_replace( char s[] )
{
char *p = s;
for ( char *q = s; *q; )
{
*p++ = *q++;
char *current = q;
while (isalpha( ( unsigned char )q[-1] ) &&
isalpha( ( unsigned char )q[0] ) &&
( unsigned char )( q[-1] + 1 ) == ( unsigned char )q[0])
{
++q;
}
if (current != q)
{
if (q - current > 1)
{
*p++ = '-';
}
*p++ = q[-1];
}
}
*p = '\0';
return s;
}
int main( void )
{
char s[] = "dabcefLMNOpQrstuv567zyx";
puts( s );
puts( sequence_replace( s ) );
}
The program output is
dabcefLMNOpQrstuv567zyx
da-cefL-OpQr-v567zyx

Checking whether a string consists of two repetitions

I am writing a function that returns 1 if a string consists of two repetitions, 0 otherwise.
Example: If the string is "hellohello", the function will return 1 because the string consists of the same two words "hello" and "hello".
The first test I did was to use a nested for loop but after a bit of reasoning I thought that the idea is wrong and is not the right way to solve, here is the last function I wrote.
It is not correct, even if the string consists of two repetitions, it returns 0.
Also, I know this problem could be handled differently with a while loop following another algorithm, but I was wondering if it could be done with the for as well.
My idea would be to divide the string in half and check it character by character.
This is the last function I tried:
int doubleString(char *s){
int true=1;
char strNew[50];
for(int i=0;i<strlen(s)/2;i++){
strNew[i]=s[i];
}
for(int j=strlen(s)/2;j<strlen(s);j++){
if(!(strNew[j]==s[j])){
true=0;
}
}
return true;
}
The problem in your function is with the comparison in the second loop: you are using the j variable as an index for both the second half of the given string and for the index in the copied first half of that string. However, for that copied string, you need the indexes to start from zero – so you need to subtract the s_length/2 value from j when accessing its individual characters.
Also, it is better to use the size_t type when looping through strings and comparing to the results of functions like strlen (which return that type). You can also improve your code by saving the strlen(s)/2 value, so it isn't computed on each loop. You can also dispense with your local true variable, returning 0 as soon as you find a mismatch, or 1 if the second loop completes without finding such a mismatch:
int doubleString(char* s)
{
char strNew[50] = { 0, };
size_t full_len = strlen(s);
size_t half_len = full_len / 2;
for (size_t i = 0; i < half_len; i++) {
strNew[i] = s[i];
}
for (size_t j = half_len; j < full_len; j++) {
if (strNew[j - half_len] != s[j]) { // x != y is clearer than !(x == y)
return 0;
}
}
return 1;
}
In fact, once you have appreciated why you need to subtract that "half length" from the j index of strNew, you can remove the need for that temporary copy completely and just use the modified j as an index into the original string:
int doubleString(char* s)
{
size_t full_len = strlen(s);
size_t half_len = full_len / 2;
for (size_t j = half_len; j < full_len; j++) {
if (s[j - half_len] != s[j]) { // x != y is clearer than !(x == y)
return 0;
}
}
return 1;
}
This loop
for(int j=strlen(s)/2;j<strlen(s);j++){
if(!(strNew[j]==s[j])){
true=0;
}
}
is incorrect. The index in the array strNew shall start from 0 instead of the value of the expression strlen( s ) / 2.
But in any case your approach is incorrect because at least you are using an intermediate array with the magic number 50. The user can pass to the function a string of any length.
char strNew[50];
The function can look much simpler.
For example
int doubleString( const char *s )
{
int double_string = 0;
size_t n = 0;
if ( ( double_string = *s != '\0' && ( n = strlen( s ) ) % 2 == 0 ) )
{
double_string = memcmp( s, s + n / 2, n / 2 ) == 0;
}
return double_string;
}
That is the function at first checks that the passed string is not empty and its length is an even number. If so then the function compares two halves of the string.
Here is a demonstration program.
#include <stdio.h>
#include <string.h>
int doubleString( const char *s )
{
int double_string = 0;
size_t n = 0;
if (( double_string = *s != '\0' && ( n = strlen( s ) ) % 2 == 0 ))
{
double_string = memcmp( s, s + n / 2, n / 2 ) == 0;
}
return double_string;
}
int main( void )
{
printf( "doubleString( \"\" ) = %d\n", doubleString( "" ) );
printf( "doubleString( \"HelloHello\" ) = %d\n", doubleString( "HelloHello" ) );
printf( "doubleString( \"Hello Hello\" ) = %d\n", doubleString( "Hello Hello" ) );
}
The program output is
doubleString( "" ) = 0
doubleString( "HelloHello" ) = 1
doubleString( "Hello Hello" ) = 0
Pay attention to that the function parameter should have the qualifier const because the passed string is not changed within the function. And you will be able to call the function with constant arrays without the need to defined one more function for constant character arrays.
it's better to do it with a while loop since you don't always have to iterate through all the elements of the string but since you want the for loop version here it is (C++ version):
int doubleString(string s){
int s_length = s.length();
if(s_length%2 != 0) {
return 0;
}
for (int i = 0; i < s_length/2; i++) {
if (s[i] != s[s_length/2 + i]){
return 0;
}
}
return 1;
}

Is there any proper way how to put integer into string? [C]

I have code like this:
char str[100];
int r = 0;
for(int k = 0; k < i;k++){
str[r++] = y[k];
sprintf(str[r], str, x[k]);
r++;
}
I want in array y I have only alphabetic characters(e.g C,D...) and in array x I have only numbers. I want to make string like "C50D80E20" etc."
But I dont know how to put interger into string(I know I´m using sprintf wrong and also that it shouldn´t be used in this case).
Thanks in advance.
Here you are.
#include <stdio.h>
int main(void)
{
enum { N = 100 };
char s[N];
char a[] = "CDE";
int b[] = { 50, 80, 20 };
int pos = 0;
for ( size_t i = 0; i + 1 < sizeof( a ); i++ )
{
pos += sprintf( s + pos, "%c%d", a[i], b[i] );
}
s[pos] = '\0';
puts( s );
return 0;
}
The program output is
C50D80E20
This statement
s[pos] = '\0';
is required only in the case when there are no values to append to the array s that is when none call of sprintf was executed.
If you want to get a string like this
C50 D80 E20
then just write for example
pos += sprintf( s + pos, "%c%d%c", a[i], b[i], ' ' );
And if you want to remove the last space character then instead of
s[pos] = '\0';
write
s[ pos == 0 ? pos : pos - 1 ] = '\0';
Instead of the function sprintf you could use the function snprintf. But it does not resolve the problem if you allocated not enough memory for the result string because in any case you will not get the expected result in such a case.
As for the function itoa then it is not a standard C function.
Use itoa().
Somthing like that:
itoa(y[k], str[r++], 10);
Here's a link about itoa().
UPDT:
Or as correctly commentator marked - you can use int + '0'
Is there any proper way how to put integer into string? [C]
Use snprintf().
Check results.
char str[N];
int len = snprintf(str[r], sizeof str, "%d", x[k]);
if (len < 0 || (unsigned)len >= sizeof str) Handle_Error();

Getting first string from string array in c

I am trying to create processes for my project. I will pas arguments to child process from parent and the argument will change in time, so i wanted to make a try first with passing 1 to the child. The string format should be like this "childname.exe c" where c represents random character (in this case it is 1 for just trial).
I created a childname array and and all i wanted was concatenate the new string with childname string and copy it to another string array(lpCommandLine variable). When i debugged the code below i saw that child_name[0] (when i is equal to 0) returns only 'C' although i expected it to return "ChildProj1.exe". Is there a point that i missed or how to do it in c?
here there is a image of what i getin debugger: here stored values of in variables
#define NO_OF_PROCESS 3
char *child_names[]= {"ChildProj1.exe", "ChildProj2.exe", "ChildProj3.exe" };
char* lpCommandLine[NO_OF_PROCESS];
int i;
for (i = 0; i < NO_OF_PROCESS; i++)
lpCommandLine[i] = (char *)malloc(sizeof(char) * 16);
for (i = 0; i < NO_OF_PROCESS; i++)
{
strcat_s(child_names[i], strlen(child_names[i]), " 1");
strcpy_s(lpCommandLine[i], strlen(lpCommandLine[i]), child_names[i]);
}
From your description it follows that you want to get strings like this
"childname.exe c"
However this loop
for (i = 0; i < NO_OF_PROCESS; i++)
{
strcat_s(child_names[i], strlen(child_names[i]), " 1");
strcpy_s(lpCommandLine[i], strlen(lpCommandLine[i]), child_names[i]);
}
does not do what you want.
This loop has undefined behavior because in this statement
strcat_s(child_names[i], strlen(child_names[i]), " 1");
there is an attempt to modify a string literal. You may not change string literals neither in C nor in C++.
Moreover in this statement
strcpy_s(lpCommandLine[i], strlen(lpCommandLine[i]), child_names[i]);
this call
strlen(lpCommandLine[i])
also has undefined behavior because array pointed to by this pointer lpCommandLine[i] does not has the terminating zero.
There is no any need to use the functions strcat_s and strcpy_s. It is much better to use standard function strcat and strcpy.
What you is the following that is shown in this demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NO_OF_PROCESS 3
int main(void)
{
const char * child_names[]=
{
"ChildProj1.exe",
"ChildProj2.exe",
"ChildProj3.exe"
};
const char *s = " 1";
size_t n = strlen( s );
char* lpCommandLine[NO_OF_PROCESS];
for ( int i = 0; i < NO_OF_PROCESS; i++ )
{
lpCommandLine[i] = ( char * )malloc( strlen( child_names[i] ) + n + 1 );
}
for ( int i = 0; i < NO_OF_PROCESS; i++ )
{
strcpy( lpCommandLine[i], child_names[i] );
strcat( lpCommandLine[i], s );
}
for ( int i = 0; i < NO_OF_PROCESS; i++ ) puts( lpCommandLine[i] );
for ( int i = 0; i < NO_OF_PROCESS; i++ ) free( lpCommandLine[i] );
return 0;
}
The program output is
ChildProj1.exe 1
ChildProj2.exe 1
ChildProj3.exe 1
Instead of char * child_names[] did you mean something like char[][] child_names, char[] * child_names, or char ** child_names?
to do the string concat do
size_t sz = strlen(child_names[i]) + 3; // space, '1' and \0
char *buff = malloc(sz);
strcat_s(buff,sz,child_names[i]);
strcat_s(buff,sz," 1");

How to manipulate the value of a char pointer from a external function in C?

I'm intending to create a function that has a similar job of the scanf, but that I will not need to define the length of my char array, only defining the pointer ( and using malloc() ).
At this point, I want to make this header file to only have to include and use it when I need.
Here is my external function, inside of string.variavel.h:
# include <stdio.h>
# include <stdlib.h>
void pegastr( char *str ){
char x , *guardaStr ;
unsigned int i , j ;
str = malloc( 1 );
str[0] = '\0';
for( j = 0 ; x != '\n' ; ++j ){
x = getc( stdin );
fflush( stdin );
guardaStr = malloc( j );
for( i = 0 ; i < j ; ++i ){
guardaStr[i] = str[i];
}
str = malloc( 1 + j );
for ( i = 0 ; i < j + 1 ; ++i ){
if( guardaStr[i] == '\0' ){
str[i] = x ;
}else{
str[i] = guardaStr[i] ;
}
}
str[i] = '\0';
}
}
And here is my function that calls and include the externals:
# include "string.variavel.h"
int main(void){
char *palavrao , *torrada;
pegastr( palavrao );
pegastr( torrada );
printf( "%s\n%s" , palavrao , torrada );
return 0;
}
So, my problem is that if I copy all code of pegastr() to inside of main(), when I try to output the string it works, but, if I don't do this and let the code stays like it is right now, when I try to output the value of the strings inside the main(), I only gets (null) at each printf().
I think that my problem is with the address that I send/receive to/from the parameters of my function pegastr(), but I don't see what I need to change more.
My thanks for all of your help!
The code you pasted has a lots of problems with memory handling. You have memory leaks and what you do there is not very clear.
I'm going to address the main problem you have here, from what I understood after reading your question. This is generally about pointers and how they work.
If you want to allocate a pointer in a function and return it, you can A) pass a pointer to the pointer or B) return the pointer.
A)
// call: myallocator(&element, size)
void myallocator(char **element, size_t size)
{
*element = malloc(size);
// ...
}
B)
// call: element = myallocator(size)
char* myallocator(size_t size)
{
char *mem;
mem = malloc(size);
// ...
return mem;
}
If I copy all your code into main, it still just prints the null. In general your program has undefined behavior and won't work (regardless of where you put the code)
Your first problem is that the function does not change the value of palavrao and torrada. The function is just called with the value of the pointers and no matter how much you change the value inside the function, the variables outside still have the same value.
Instead you can do it like:
void pegastr( char **str ){ // Note double pointer
....
*str = malloc(....
}
// Called like
pegastr( &palavrao );
or like
char* pegastr(){ // Return the malloc'ed pointer
char * tmp = malloc(....
....
return tmp;
}
// Called like
palavrao = pegastr();
Besides that your code have quite a number of things you need to fix:
for( j = 0 ; x != '\n' ; ++j ){
^
x is uninitialized when the loop starts
and
guardaStr = malloc( j );
^
Do you want this when j is 0 ?
Or do you really want j + 1 here ?
Further you you have memory leak when you run this code the 2nd, 3rd, ... time. You need to free the memory before overwrint the old pointer with a new pointer.
The memory leak also applies to:
str = malloc( 1 + j );
And here:
if( guardaStr[i] == '\0' ){
^^^^^^^^^^^^
Access outside allocated memory (e.g. when j is 0)
I'll suggest that you read about realloc - it is a better choice for your code.
Using realloc the code could be something like:
# include <stdio.h>
# include <stdlib.h>
void pegastr( char **str ){
char *tmp;
char x;
unsigned int j ;
tmp = malloc( 1 );
if (tmp == NULL)
{
// Out of memory
exit(1);
}
str[0] = '\0';
j = 1; // Notice: j starts from 1
while(1){
x = getc( stdin );
if (x == '\n')
{
// Don't copy the \n - just break the loop
break;
}
fflush( stdin );
// Insert the new char and a termination
tmp = realloc(tmp, j+1);
if (tmp == NULL)
{
// Out of memory
exit(1);
}
tmp[j-1] = x;
tmp[j] = '\0';
// Increment j
++j;
}
// Update the input pointers value
*str = tmp;
}
int main(void){
char *palavrao , *torrada;
pegastr( &palavrao );
pegastr( &torrada );
printf( "%s\n%s\n" , palavrao , torrada );
free(palavrao);
free(torrada);
return 0;
}

Resources