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;
}
Related
I had an exam yesterday in which one of the questions was about counting words in a given string.
The definition of word would be a portion of a string that is divided by spaces and/or the beginning/end of the string
I am new to C, and was not able to create a condition where it increases the counter word when you find “space (characters) space”
int count_words(char *str)
int i = 0;
int word = 2;
while (str[i])
{
if (str[i] == ‘ ‘)
{
int l = 1;
while (str[i + l]
{
l++;
}
if (l != 1)
{
word++;
}
}
}
For starters the function should be declared like
size_t count_words(const char *str);
The function parameter should be declared with the qualifier const because the passed string is not being changed within the function and the function return type should be size_t that is the same return type as for example of standard string function strlen.
It is unclear why the variable word in your function is initialized by 2
int word = 2;
Or the variable i is not being changed within the function.
The function can look the following way as shown in the demonstration program below
#include <ctype.h>
#include <string.h>
#include <stdio.h>
size_t count_words( const char *s )
{
size_t n = 0;
while ( *s )
{
while ( isspace( ( unsigned char )*s ) ) ++s;
if ( *s )
{
++n;
while ( *s && !isspace( ( unsigned char )*s ) ) ++s;
}
}
return n;
}
int main( void )
{
const char *s = "How to write a function in c that counts words";
size_t n = count_words( s );
printf( "The string \"%s\"\ncontains %zu words\n", s, n );
}
The program output is
The string "How to write a function in c that counts words"
contains 10 words
If to use as delimiters only the space character ' ' then the header <ctype.h> should be removed and the function will look like
size_t count_words( const char *s )
{
size_t n = 0;
while ( *s )
{
while ( *s == ' ' ) ++s;
if ( *s )
{
++n;
while ( *s && *s != ' ' ) ++s;
}
}
return n;
}
A more general function that can process any delimiters can look the following way
size_t count_words( const char *s, const char *delim )
{
size_t n = 0;
while (*s)
{
s += strspn( s, delim );
if (*s)
{
++n;
s += strcspn( s, delim );
}
}
return n;
}
The function has a second parameter that specifies delimiters. For example the function can be called loke
size_t n = count_words( s, " \t?!:;,." );
Try this way:
# include<stdio.h>
# include<string.h>
# define MaxBufferSize 50
void main(){
int count =0, size;
char str[MaxBufferSize+2];
printf("Enter string(max char 50 only): ");
if(fgets(str,sizeof(str), stdin)) {
if(strlen(str) > MaxBufferSize) printf("Max chars exceeded so chars before the limit were used!!!\n");
str[strcspn(str, "\n")] = '\0';
}
size = strlen(str);
int i=0;
if(size == 0) printf("Nothing entered\n");
else {
while(i<size){
while(!isalnum(str[i]) && i<size) i++;// ignores all spaces and other chars
if(str[i] == '\0') break;
while(isalnum(str[i]) && i<size) i++;// includes all words and numbers
count++;
}
printf("Words in string: %d\n",count);
}
}
hope it helps...! ;)
#include <stdio.h>
int count_words(char *str) {
int i, count=0;
int in_word = 0; // Flag to track if we're currently inside a word or not
// Loop through each character in the string
for(i=0; str[i]!='\0'; i++) {
// If current character is not a space or newline and we're not already inside a word, increment word count
if((str[i]!=' ' && str[i]!='\n') && !in_word) {
count++;
in_word = 1; // Set flag to indicate we're currently inside a word
}
// If current character is a space or newline, set flag to indicate we're not inside a word
else if(str[i]==' ' || str[i]=='\n') {
in_word = 0;
}
}
return count;
}
#include <stdio.h>
#include <string.h>
void main()
{
char s[200];
int count = 0, i;
printf("Enter the string:\n");
scanf("%[^\n]s", s);
for (i = 0;s[i] != '\0';i++)
{
if (s[i] == ' ' && s[i+1] != ' ')
count++;
}
printf("Number of words in given string are: %d\n", count + 1);
}
Use this code it will definitely works fine ):
I am trying to write a function that takes in variables cipher, userinput, alphabet and outputs the replace letters. for example at execution it takes in an argument argv ZYXWVUTSRQPONMLKJIHGFEDCBA. requests a user to input anything then switches only the letters for example input aBc should output zYx
// function that takes in cipher(c), userinput(u) and alphabet(a) and outputs cipher text
void cipher_text(string c, string u, string a)
{
string result = u;
for (int i = 0; i < strlen(u); i++)
{
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
}
// printf("ciphertext: %s\n", result);
}
with cipher as YUKFRNLBAVMWZTEOGXHCIPJSQD
and userinput as abcd
I was expecting yukf but got qidc
The problem of the function is this inner for loop
for (int k = 0; k < strlen(a); k++)
{
if (tolower(u[i]) == a[k])
{
if(islower(u[i]))
{
result[i] = tolower(c[k]);
printf("%s %s\n",result,c);
}
else
{
result[i] = toupper(c[k]);
}
}
}
You need to break it as soon as a letter is found in the string pointed to by the pointer a. Otherwise there can be a chain of changes.
Also using the function strlen is inefficient and redundant.
Instead of the for loop you could use standard function strchr.
The function can be declared and defined the following way
string cipher_text( string c, string u, string a )
{
for ( string p = u; *p != '\0'; p++ )
{
string pos = strchr( a, tolower( ( unsigned char )*p ) );
if ( pos != NULL )
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
Pay attention to that instead of the typedef name string it is better to use its underlaying type char *.
In this case the function can look the following way as shown in the demonstration program below.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char * cipher_text( const char *c, char *u, const char *a )
{
for (char *p = u; *p != '\0'; p++)
{
const char *pos = strchr( a, tolower( ( unsigned char )*p ) );
if (pos != NULL)
{
size_t i = pos - a;
*p = islower( ( unsigned char )*p )
? tolower( c[i] )
: c[i];
}
}
return u;
}
int main( void )
{
const char *c = "XYZ";
const char *a = "abc";
char u[] = "c_B_a";
puts( cipher_text( c, u, a ) );
}
The program output is
z_Y_x
I have assignment that to use function char *slova(const char *s) which returns dynamically allocated string that is only made of small and big letters. It's forbidden to use string.h library.
char *slova(const char *s)
{
char *new;
int br = 0;
new = (char *)malloc(sizeof(s));
for (int i = 0; i != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z')
{
new[br] = s[i];
br++;
}
return new;
}
I know there are some other characters other than small and big letters between A and z in ASCII code, so don't worry about that. For some reason this code doesn't work and I don't know why.
sizeof(s) will return not the buffer size but the size of the pointer s.
i != '\0' is wrong. This means i != 0 and prevent it from entering the loop because initial value of i is 0.
You forgot to terminate the resulting string by adding a terminating null-character.
Casting the result of malloc() in C is discouraged.
Fixed code:
char *slova(const char *s){
char *new;
int br = 0;
// calculate the length
for (int i = 0; s[i] != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z'){
br++;
}
// allocate buffer
new = malloc(br + 1);
if (new == NULL) return NULL;
// actually create the string
br = 0;
for (int i = 0; s[i] != '\0'; i++)
if(s[i] >= 'A' && s[i] <= 'z'){
new[br] = s[i];
br++;
}
new[br] = '\0';
return new;
}
Look carefully at your function declaration
char *slova(const char *s){
^^^^^^^^^^^^^
Its parameter has the pointer type const char *. Thus in this statement
new = (char *)malloc(sizeof(s));
the expression sizeof(s) yields the size of a pointer that usually is equal to 8 or 4 bytes depending on the used system. That is this expression does not provide the length of the passed string.
Also the body of this loop
for (int i = 0; i != '\0'; i++)
never gets the control because the condition i != '\0' at once evaluates to false because the variable i was initialized by zero.
The function can look the following way as it is shown in the demonstrative program below. It does not use functions from the header <string.h>.
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
char * slova( const char *s )
{
size_t n = 0;
for ( const char *t = s; *t != '\0'; ++t )
{
if ( isalpha( ( unsigned char )*t ) ) ++n;
}
char * result = malloc( ( n + 1 ) *sizeof( char ) );
if ( result != NULL )
{
char *p = result;
for ( ; *s; ++s)
{
if ( isalpha( ( unsigned char )*s ) )
{
*p++ = *s;
}
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "H#e#l#l#o W#o#r#l#d";
char *p = slova( s );
if ( p ) puts( p );
free( p );
return 0;
}
The program output is
HelloWorld
If you are not allowed also to use functions from the header <ctype.h> then the function can look the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
char * slova( const char *s )
{
const char *upper_case = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char *lower_case = "abcdefghijklmnopqrstuvwxyz";
size_t n = 0;
for ( const char *t = s; *t != '\0'; ++t )
{
const char *letter = lower_case;
if ( *t < lower_case[0] )
{
letter = upper_case;
}
while ( *letter && *letter < *t ) ++letter;
if ( *letter == *t ) ++n;
}
char * result = malloc( ( n + 1 ) *sizeof( char ) );
if ( result != NULL )
{
char *p = result;
for ( ; *s; ++s)
{
const char *letter = lower_case;
if ( *s < lower_case[0] )
{
letter = upper_case;
}
while ( *letter && *letter < *s ) ++letter;
if ( *letter == *s )
{
*p++ = *s;
}
}
*p = '\0';
}
return result;
}
int main(void)
{
const char *s = "H#e#l#l#o W#o#r#l#d";
char *p = slova( s );
if ( p ) puts( p );
free( p );
return 0;
}
Again the program output is
HelloWorld
What does the bold part stand for in this code? I've managed to fulfill most of the template (given by my teacher as assignment), can't find the reason behind that bold part.
I could use the strlen part before it appeared, I know one can still write the code without strlen at all.
#include <stdio.h>
int strlen(char *str)
{
int c = 0;
while (str[c] != '\0')
{
c++;
}
return c;
}
int isPalindrome(char *str)
{
char *ptr1 = str;
char *ptr2 = str + strlen(str) - 1;
while (ptr2 > ptr1)
{
if (tolower(*ptr1) != tolower(*ptr2))
{
return (0);
}
ptr1++;
ptr2--;
}
return (1);
}
/**
This function will
-return 1 if the given string is Palindrome,
-return 0 if the given string is not Palindrome.
*/
**int n = strlen(str);
// Write your code here**
}
int main()
{
char *str = "ABCCBA ABCCBA"; //your input
if (isPalindrome(str))
{
printf("%s is a palindrome", str);
}
else
{
printf("%s is not a palindrome", str);
}
}
The teacher hinted that using the length of the zero-terminated input string will be needed. They stored that useful value inside a variable.
If you are required to use the code provided by the teacher, then move all your code AFTER that line and within your code replace the strlen(str) with n.
int isPalindrome(char *str)
{
/**
This function will
-return 1 if the given string is Palindrome,
-return 0 if the given string is not Palindrome.
*/
int n = strlen(str);
// Write your code here
char *ptr1 = str;
char *ptr2 = str + n - 1;
while (ptr2 > ptr1)
{
if (tolower(*ptr1) != tolower(*ptr2))
{
return (0);
}
ptr1++;
ptr2--;
}
return (1);
}
You can implement isPalindrome without any knowledge about pointers.
I prefer to use indices instead of pointers, look at the next example
#include <stdio.h>
#include <assert.h>
int strLen(const char *str)
{
int n = 0;
while(str[n]) { ++n; }
return n;
}
int isPalindrome(const char *str) {
int i = 0;
int j = strLen(str) - 1;
while (i < j) {
if (str[i++] != str[j--]) { return 0; }
}
return 1;
}
int main() {
assert(isPalindrome(""));
assert(isPalindrome("a"));
assert(isPalindrome("aa"));
assert(isPalindrome("aba"));
assert(!isPalindrome("ab"));
assert(!isPalindrome("aab"));
}
I think that the function template starts from the declaration of the variable n that gets the size of the passed string.
int isPalindrome(char *str)
{
/**
This function will
-return 1 if the given string is Palindrome,
-return 0 if the given string is not Palindrome.
*/
int n = strlen(str);
// Write your code here*
}
But you ignored this declaration and used the expression strlen( str ) in this declaration
char *ptr2 = str + strlen(str) - 1;
instead of writing for example
int n = strlen(str);
//...
char *ptr2 = str + n - 1;
In any case the assignment looks not very well. For example this declaration
char *ptr2 = str + strlen(str) - 1;
can invoke undefined behavior when the passed string is empty.
The functions' parameters should be declared with the qualifier const because passed strings as arguments are not changed in the functions.
The argument of the standard function tolower must be converted to the type unsigned char.
The functions could look the following way
size_t strlen( const char *str )
{
size_t n = 0;
while ( str[n] ) ++n;
return n;
}
int isPalindrome( const char *str )
{
const char *ptr1 = str;
const char *ptr2 = str + strlen( str );
if ( ptr1 != ptr2 )
{
while ( ptr1 < --ptr2 &&
tolower( ( unsigned char )*ptr1 ) == tolower( ( unsigned char )*ptr2 ) )
{
++ptr1;
}
}
return !( ptr1 < ptr2 );
}
Also if the function strlen also must use pointers then it can look the following way
size_t strlen( const char *str )
{
const char *p = str;
while ( *p ) ++p;
return p - str;
}
Here is a demonstration how your functions should look.
#include <stdio.h>
#include <ctype.h>
size_t strlen( const char *str )
{
const char *p = str;
while ( *p ) ++p;
return p - str;
}
int isPalindrome( const char *str )
{
const char *ptr1 = str;
const char *ptr2 = str + strlen( str );
if ( ptr1 != ptr2 )
{
while ( ptr1 < --ptr2 &&
tolower( ( unsigned char )*ptr1 ) == tolower( ( unsigned char )*ptr2 ) )
{
++ptr1;
}
}
return !( ptr1 < ptr2 );
}
int main(void)
{
char *str = "ABCCBA ABCCBA"; //your input
if ( isPalindrome( str ) )
{
printf("\"%s\" is a palindrome\n", str);
}
else
{
printf("\"%s\" is not a palindrome\n", str);
}
return 0;
}
The program output is
"ABCCBA ABCCBA" is a palindrome
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;
}