While loop error while implementing 'strend' - c

I keep getting errors when I run the program I wrote for 'strlen'. (strlen returns 1 when one string appears at the end of another). I guess it's the first while loop that gives the error, because when I put printf("%c\n", *s); instead of empty ;, it just works fine. Is there something wrong with the syntax???
#include <stdio.h>
int strend(char *s, char *t)
{
int len;
int dummy;
while ( *s++ )
; // why error???
while ( *t++ )
len++;
for ( ; len>0 ; len--)
{
if ( *(s-len) != *(t-len) )
return 0;
}
return 1;
}
int main() {
char one[] = "I 0dont like youa";
char two[] = "ke youa";
printf("%d\n", strend(one, two));
}

First of all you forgot to initialize len, you should initialize it with 0.
int len=0;
Secondly use this:
while ( *s )
s++; // s should be incremented only if *s is not 0.
while ( *t )
{
t++; //Same issue here.
len++;
}

First of all local variable len was not initialized
int len;
So the function already has undefined behaviour.
Second after the loops
while ( *s++ );
while ( *t++ ) len++;
the both pointers point to beyond the terminating zeroes of each strings. As result this comparison (along with the for loop itself)
if ( *(s-len) != *(t-len) )
is not valid.
Indeed let's assume that we have
char s[] = { 'a', '\0' };
char t[] = { 'a', '\0' };
After the above loops len will be equal to 1 (provided that initially you initialized len with 0 ). At the same time t and s will point to the memory after the terminating zero. So *( s - len ) and *( t - len ) will represent elements '\0' and you will compare only these terminating zeroes while the elements with 'a' will not be compared because the condition of the for loop is len>0. That means that there will be only one iteration of the loop when len is equal to 1.
A correct function can be written simpler and more clear
int strend( const char *s, const char *t )
{
const char *p = s;
const char *q = t;
while ( *s++ );
while ( *t++ );
while ( s != p && t != q && *( s - 1 ) == *( t - 1 ) ) --s, --t;
return t == q;
}
If it is unimportant which one string appears at the end of another string then simply substitute this return statement
return t == q;
for the following one
return s == p || t == q;
In this case this program
//...
int main( void ) {
char one[] = "I 0dont like youa";
char two[] = "ke youa";
printf("%d\n", strend(one, two));
printf("%d\n", strend(two, one));
}
will output
1
1
While if to use use the first return statement return t == q; then the program
//...
int main( void ) {
char one[] = "I 0dont like youa";
char two[] = "ke youa";
printf("%d\n", strend(one, two));
printf("%d\n", strend(two, one));
}
will output
1
0

The error should come because of the missing initialization int len = 0;. I recommend using while always with embraces like this while { /*your code*/ };.
Your 1st while loop should be fine anyway. I made some modifications with two separated loops.
#include <stdio.h>
int strend(char *s, char *t)
{
int len = 0; // init 0
int i = 0,
j = 0;
while (*s++) { i++; } // get both string lengths
while (*t++) { j++; }
if (i > j) // compare and use shorter one
len = j;
else
len = i;
len++; // offset: start from 1st character
// [fix-issue: 2015-06-28 12:41]
for ( ; len>0 ; len--)
{
//printf("%d: \"%c\" \"%c\"\n", len, *(s-len), *(t-len)); // test-out
if ( *(s-len) != *(t-len) )
return 0;
}
return 1;
}
int main()
{
char one[] = "ABCDE";
char two[] = "CDE";
printf("test case 1: [%s][%s] %d\n", one, two, strend(one, two));
two[1] = '_';
printf("test case 2: [%s][%s] %d\n", one, two, strend(one, two));
two[0] = '?';
two[1] = 'D';
printf("test case 3: [%s][%s] %d\n", one, two, strend(one, two));
two[0] = 'C';
two[2] = '#';
printf("test case 4: [%s][%s] %d\n", one, two, strend(one, two));
}
The output goes like this:
test case 1: [ABCDE][CDE] 1
test case 2: [ABCDE][C_E] 0
test case 3: [ABCDE][?DE] 0
test case 4: [ABCDE][CD#] 0

Related

Doubling all occurrences of a specific character in a string

I want to write a C program, that returns a new string allocated on the heap. This string is obtained by doubling all occurrences of “c” in a string (“abcdc” becomes “abccdcc” after doubling “c”).
This is my code and I don't really see where the problem is to fix it!
size_t taille = stringLength(str);
size_t k=0;
size_t q=0;
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
char *nouvelle=malloc(taille+1+k);
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
nouvelle[j]=str[i];
}
else
{
j=i;
++q;
nouvelle[j]=str[i];
j=i+q;
nouvelle[j++]=str[i];
}
++i;
}
nouvelle[taille+1+k]='\0';
return nouvelle;
}
There are two problems with your code.
The first one is that after this while loop
while (*str!='\0')
{
if (*str == c)
{
k=k+1;
}
++str;
}
the pointer str points to the end of the string that is to the terminating zero character '\0'.
The second one is that you are using the uninitialized variable i
int i,j= 0;
while(*str !='\0')
{
if (str[i] != c)
{
j=i;
//..
This declaration
int i,j= 0;
is not the same as
int i = 0,j= 0;
That is only the variable j is initialized by 0.
And the statement
j = i;
does not make sense.
Also it is unclear whether c denotes a variable or the character 'c'. If you mean the character 'c' then you need to write at least like
if (*str == 'c')
You could define the function for example the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char * duplicate_char( const char *s, char c )
{
size_t n = 0;
for (const char *p = s; *p; ++p)
{
if (*p == c) ++n;
}
char *nouvelle = malloc( strlen( s ) + n + 1 );
if (nouvelle)
{
if (n == 0)
{
strcpy( nouvelle, s );
}
else
{
char *p = nouvelle;
while (*s)
{
*p++ = *s++;
if (p[-1] == c) *p++ = c;
}
*p = '\0';
}
}
return nouvelle;
}
int main( void )
{
char *nouvelle = duplicate_char( "abcdc", 'c' );
if (nouvelle != NULL) puts( nouvelle );
free( nouvelle );
}
The program output is
abccdcc
If you want to use your own function stringLength instead of the standard C function strlen then it can look like
size_t stringLength( const char *s )
{
const char *p = s;
while ( *p ) ++p;
return p - s;
}

Print pointer string which is return from function in C

Trying to write a C program to reverse the given string (using Pointer) and here is the code.
[sample.c]
#include <stdio.h>
#include <stdlib.h>
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i;
}
char *_reverse(char s[])
{
int len = _len(s);
char *r = malloc(len * sizeof(char));
for (int i=len-1; i >= 0; i--) {
*r++ = s[i];
}
*r = '\0'; // Line 21
r -= len; // Line 22
return r;
}
int main(int argc, char *argv[])
{
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Current O/P:
Actual String: Hello
Reversed: (null)
Expected O/P:
Actual String: Hello
Reversed: olleH
What is wrong or missing in here..? Please correct me. Thanks in advance.
You are modifying the pointer "r" of your newly allocated memory. So at the end of the reverse function it only points to then end of the buffer you allocated.
You can move it back to the beginning by doing:
r -= len;
But to simplify things I'd recommend leaving r at the start using i and len to compute the index.
Also, you don't terminate the reversed string with a '\0'.
You increase r in the loop, then return it. Obviously, it points to an address after the actual reversed string. Copy r to another variable after malloc and return that.
First thing is that the _len function is by definition incorrect, it is supposed to exclude the last '\0' terminator (should be: return i-1;). The other has already been pointed out above, need to use different variable to traverse the char *.
#include <stdio.h>
#include <stdlib.h>
int _len(char s[]) {
int i = 0;
while (s[i++] != '\0');
return i-1;
}
char *_reverse(char s[]) {
int len = _len(s);
//printf("Len: %d\n", len);
char *r = (char *) malloc((len+1) * sizeof(char));
char *ptr = r;
for (int i=len-1; i >= 0; i--) {
//printf("%d %c\n", i, s[i]);
*(ptr++) = s[i];
}
*(ptr++) = '\0';
return r;
}
int main(int argc, char *argv[]) {
char s[10] = "Hello";
printf("Actual String: %s\n", s);
printf("Reversed: %s\n", _reverse(s));
return 0;
}
Actual String: Hello
Reversed: olleH
The first function implementation
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
return i; // Old code
}
though has no standard behavior and declaration nevertheless is more or less correct. Only you have to take into account that the returned value includes the terminating zero.
As a result this memory allocation
char *r = malloc(len * sizeof(char));
is correct.
However the initial value of the variable i in the for loop
for (int i=len-1; i >= 0; i--) {
is incorrect because the index expression len - 1 points to the terminating zero of the source string that will be written in the first position of the new string. As a result the new array will contain an empty string.
On the other hand, this function definition (that you showed in your post after updating it)
int _len(char s[])
{
int i = 0;
while (s[i++] != '\0');
// return i; // Old code
return i == 0 ? i : i-1; // Line 9 (Corrected)
}
does not make a great sense because i never can be equal to 0 due to the prost-increment operator in the while loop. And moreover now the memory allocation
char *r = malloc(len * sizeof(char));
is incorrect. There is no space for the terminating zero character '\0'.
Also it is a bad idea to prefix identifiers with an underscore. Such names can be reserved by the system.
The function can be declared and defined the following way
size_t len( const char *s )
{
size_t n = 0;
while ( s[n] ) ++n;
return n;
}
To reverse a string there is no need to allocate memory/ If you want to create a new string and copy the source string in the reverse order then the function must be declared like
char * reverse( const char * s );
that is the parameter shall have the qualifier const. Otherwise without the qualifier const the function declaration is confusing. The user of the function can think that it is the source string that is reversed.
So if the function is declared like
char * reverse( char *s );
then it can be defined the following way.
char * reverse( char *s )
{
for ( size_t i = 0, n = len( s ); i < n / 2; i++ )
{
char c = s[i];
s[i] = s[n - i - 1];
s[n - i - 1] = c;
}
return s;
}
If you want to create a new string from the source string in the reverse order then the function can look like
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *result = malloc( len + 1 );
if ( result != NULL )
{
size_t i = 0;
while ( n != 0 )
{
result[i++] = s[--n];
}
result[i] = '\0';
}
return result;
}
And you should not forget to free the result array in main when it is not needed any more.
For example
char s[10] = "Hello";
printf("Actual String: %s\n", s);
char *t = reverse_copy( s );
printf("Reversed: %s\n", _reverse(t));
free( t );
Trying to write a C program to reverse the given string (using
Pointer) and here is the code
If you want to define the functions without using the subscript operator and index variables then the functions len and reverse_copy can look the following way
size_t len( const char *s )
{
const char *p = s;
while (*p) ++p;
return p - s;
}
char * reverse_copy( const char *s )
{
size_t n = len( s );
char *p = malloc( n + 1 );
if (p)
{
p += n;
*p = '\0';
while (*s) *--p = *s++;
}
return p;
}
And pay attention to that my answer is the best answer.:)

Replacing several characters in string with one in C

I need to replace several characters with one (depending if their count is even or odd). If it's even i should replace + with P, if it's odd with p.
Input: kjlz++zux+++
while(p[i])
{
j=i;
k=i;
length=strlen(p);
if(p[i]=='*')
{
position=i;
}
printf("Position is: %d", position);
while(p[j]=='*')
{
counter++;
j++;
}
}
Output: kjlzPzuxp
Im not sure how to remove several characters I know how to input one.
Basically you can leave the text variable intact until you find a +. In that case you start counting how many consecutive plusses there are. Once you know this, it can be decided if you should add a letter P or p. Keep a separate index to write back to your text variable! Otherwise it would start writing to the wrong index after 2 or 3 plusses are found, try to figure out why ;).
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
char text[] = "kjlz++zux+++";
int len = sizeof(text) / sizeof(text[0]);
int index = 0, count = 0;
for(int i = 0; i < len; i++)
{
if(text[i] == '+')
{
count = 0;
while(text[i] == '+') i++, count++;
i--;
text[index++] = count % 2 ? 'p' : 'P';
}
else
{
text[index++] = text[i];
}
}
text[index] = 0;
printf(text);
}
You could allocate space for the text variable with malloc so that you can use realloc afterwards to shrink the array to the size of the output text. This way some memory is saved, this is especially important when you start working with bigger chunks of data.
If I have understood correctly you do not know how to implement a corresponding function.
It can look the following way as it is shown in the demonstrative program.
#include <stdio.h>
char * replace_pluses( char *s )
{
const char plus = '+';
const char odd_plus = 'p';
const char even_plus = 'P';
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == plus )
{
int odd = 1;
while ( *++src == plus ) odd ^= 1;
*dsn++ = odd ? odd_plus : even_plus;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_pluses( s ) );
return 0;
}
The program output is
kjlz++zux+++
kjlzPzuxp
Or you can write a more generic function like this
#include <stdio.h>
char * replace_odd_even_duplicates( char *s, char c1, char c2, char c3 )
{
char *dsn = s;
for ( char *src = s; *src; )
{
if ( *src == c1 )
{
int odd = 1;
while ( *++src == c1 ) odd ^= 1;
*dsn++ = odd ? c2 : c3;
}
else
{
if ( dsn != src ) *dsn = *src;
++dsn;
++src;
}
}
*dsn = '\0';
return s;
}
int main(void)
{
char s[] = "kjlz++zux+++";
puts( s );
puts( replace_odd_even_duplicates( s, '+', 'p', 'P' ) );
return 0;
}

Splitting a string into chunks.

I'm trying to split a string into chunks of 6 using C and I'm having a rough time of it. If you input a 12 character long string it just prints two unusual characters.
#include <stdio.h>
#include <string.h>
void stringSplit(char string[50])
{
int counter = 0;
char chunk[7];
for (unsigned int i = 0; i < strlen(string); i++)
{
if (string[i] == ' ')
{
continue;
}
int lastElement = strlen(chunk) - 1;
chunk[lastElement] = string[i];
counter++;
if (counter == 6)
{
printf(chunk);
memset(chunk, '\0', sizeof chunk);
counter = 0;
}
}
if (chunk != NULL)
{
printf(chunk);
}
}
int main()
{
char string[50];
printf("Input string. \n");
fgets(string, 50, stdin);
stringSplit(string);
return(0);
}
I appreciate any help.
Your problem is at
int lastElement = strlen(chunk) - 1;
Firstly, strlen counts the number of characters up to the NUL character. Your array is initially uninitialized, so this might cause problems.
Assuming your array is filled with NULs, and you have, let's say, 2 characters at the beginning and you are looking to place the third one. Remember that your 2 characters are at positions 0 and 1, respectively. So, strlen will return 2 (your string has 2 characters), you subtract one, so the lastElement variable has the value 1 now. And you place the third character at index 1, thus overwriting the second character you already had.
Also, this is extremely inefficient, since you compute the number of characters each time. But wait, you already know how many characters you have (you count them in counter, don't you?). So why not use counter to compute the index where the new character should be placed? (be careful not to do the same mistake and overwrite something else).
The function is wrong.
This statement
int lastElement = strlen(chunk) - 1;
can result in undefined behavior of the function because firstly the array chunk is not initially initialized
char chunk[7];
and secondly after this statement
memset(chunk, '\0', sizeof chunk);
the value of the variable lastElement will be equal to -1.
This if statement
if (chunk != NULL)
{
printf(chunk);
}
does not make sense because the address of the first character of the array chunk is always unequal to NULL.
It seems that what you mean is the following.
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[] )
{
const size_t N = 6;
char chunk[N + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == N )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
stringSplit( s );
}
The program output is
Youand
Iarebe
ginner
sinC
You can modify the function such a way that the length of the chunk was specified as a function parameter.
For example
#include <stdio.h>
#include <ctype.h>
void stringSplit( const char s[], size_t n )
{
if ( n )
{
char chunk[n + 1];
size_t i = 0;
for ( ; *s; ++s )
{
if ( !isspace( ( unsigned char )*s ) )
{
chunk[i++] = *s;
if ( i == n )
{
chunk[i] = '\0';
i = 0;
puts( chunk );
}
}
}
if ( i != 0 )
{
chunk[i] = '\0';
puts( chunk );
}
}
}
int main(void)
{
char s[] = " You and I are beginners in C ";
for ( size_t i = 3; i < 10; i++ )
{
stringSplit( s, i );
puts( "" );
}
}
The program output will be
You
and
Iar
ebe
gin
ner
sin
C
Youa
ndIa
rebe
ginn
ersi
nC
Youan
dIare
begin
nersi
nC
Youand
Iarebe
ginner
sinC
YouandI
arebegi
nnersin
C
YouandIa
rebeginn
ersinC
YouandIar
ebeginner
sinC

Function that convert int to array of char, some questions

This code need to get an int number and convert it to array of char that present the number:
for example :
The number 324
convert to this:
like:
char newstr [6] = {'3','2','4','\0','\0','\0'};
I think that '\0' is null, right?
What is wrong with my code ?
also how can I change this to a function that get an int number and return array of char that present it?
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void main ()
{
int value = 324;
char str [6];
char newstr [6];
int pointer, i = 0;
for(i=0; value>0; i++)
{
str[i] = value%10 + '0';
value /=10;
}
str[i] = '\0';
for(i=5; i>-1; i--)
{
if(str[i]!='\0')
{
newstr[pointer] = str[i];
pointer++;
}
}
for (i = 0; i < 6; i++)
{
printf("%d %c\n", i, newstr[i] );
}
printf ("shalom");
}
An easy way should be calling sprintf().
char newstr[6] = {0};
sprintf(newstr, "%d", value);
In your existing code, str looks lile {'4', '2', '3', '\0', SomethingRandom, SomethingRandom}. Reversing it and assign to newstr makes it {SomethingRandom, SomethingRandom, '\0', '3', '2', '4'}, which is definitely not what you want. And indeed you don't assign newstr when str[i] == '\0', which means newstr[2] == SomethingRandom.
Try the following
#include <stdio.h>
#include <stdlib.h>
char * itoa( int x )
{
const unsigned int BASE = 10;
unsigned int u = abs( x );
size_t n = 0;
unsigned int tmp = u;
char *s;
do { ++n; } while ( tmp /= BASE );
n += x < 0;
s = malloc( ( n + 1 ) * sizeof( char ) );
s[n] = '\0';
do
{
s[--n] = u % BASE + '0';
} while ( u /= BASE );
if ( x < 0 ) s[--n] = '-';
return s;
}
int main(void)
{
char *s = itoa( -1234567890 );
printf( "%s\n", s );
free( s );
return 0;
}
The output is
-1234567890
As for your question what is wrong with your code then it is entirely wrong.:)
For example the code ignores numbers that are equal to zero. Variable pointer was not initialized
int pointer, i = 0;
each loop deals with some garbage and so on.
It will be more helpful for you if you will investigate my code.
OP's code looks very close to being correct for limited usage.
Do not start with value>0 test, otherwise when value == 0, the result will be "". Be sure to limit the number of iterations to not exceed the array size.
do {
str[i] = value%10 + '0';
value /=10;
i++;
} while (value>0 && i < (6-1));
Set '\0' in a loop. #timra points out random unset elements.
do {
str[i] = '\0';
i++;
} while (i < (6-1));
OP still has 2 remaining issues which OP has yet to specify what to do:
Values greater than 99999
Values < 0
BTW: "I think that '\0' is null, right?" '\0' is the "null character". This differs from NULL, the "null pointer".
"how can I change this to a function that get an int number and return array of char that present it"
OP's code has a number of corner problems. Suggest a new approach.
Perform conversion into local array and then return a copy of it.
Calling code should eventually free() it.
#include <limits.h>
// max size needed for int. Note 10/33 just greater than log(2)
#define INTSIZE_MAX (sizeof int * CHAR_BIT * 10 / 33 + 3)
char *intoa_alloc(int x) {
char buf[INTSIZE_MAX];
char *p = &buf[sizeof buf - 1];
// Work with negative absolute value to cope with INT_MIN
// This avoids portability problems with abs(x) approach.
int x_negative = x < 0 ? x : -x;
// Form string
*p = '\0';
do {
*--p = '0' - x_negative % 10;
x_negative /= 10;
} while (x_negative);
if (x < 0) {
*--p = '-';
}
char *dest = malloc(strlen(p) + 1);
if (dest) {
strcpy(dest, p);
}
return dest;
}
In this simple way you can do that.
int main()
{
char str [6] = "324";
printf ("%c",str[1]);
return 0;
}

Resources