applying cipher code given as argv to userinput - c

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

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;
}

How to return a new string in a function in c?

Hello my function should print str1 beginning with str2 (if found), I would like to return a new string (newStr) in the following function but it doesn't work. Some help please
char *myFunction(char *str1, char *str2){
int strLen;
int i;
int j;
char temp;
char *newStr;
strLen=0;
while(str1[strLen]!='\0'){
strLen++;
}
i=0;
j=0;
while(i<=strLen && str1[i]!='\0'){
if(str1[i]==str2[j] ){
newStr[i]=str1[i];
j++;
} else {
newStr[i]=str1[i];
}
i++;
}
return (newStr);
}
char *newStr is uninitialized; you must allocate memory to it, before assigning any value to it.
Allocate memory using malloc or calloc.
For starters the function should be declared like
char * myFunction( const char *str1, const char *str2 );
because the passed strings are not being changed within the function.
If the function has to return a new string then you need to allocate a character array where the string will be stored. However you are using an uninitialized pointer newStr
char *newStr;
The condition in the while loop
while(i<=strLen && str1[i]!='\0'){
does not make a great sense.
The variable j in fact is not used.
The if-else statement within the while loop does not make a sense.
If you are allowed to use standard C string functions then your function can be implemented very easy.
#include <string.h>
char * myFunction( const char *s1, const char *s2 )
{
char *p = strstr( s1, s2 );
if ( p != NULL )
{
size_t n = strlen( p );
s1 = p;
p = malloc( n + 1 );
if ( p != NULL ) memcpy( p, s1, n + 1 );
}
return p;
}
Otherwise the function can be defined the following way
char * myFunction( const char *s1, const char *s2 )
{
size_t n1 = 0;
while ( s1[n1] ) ++n1;
size_t n2 = 0;
while ( s2[n2] ) ++n2;
char *p = NULL;
if ( !( n1 < n2 ) )
{
int found = 0;
size_t i = 0;
while ( !found && i < n1 - n2 + 1 )
{
if ( s1[i] == s2[0] )
{
size_t j = 1;
while ( j < n2 && s1[i + j] == s2[j] ) ++j;
found = j == n2;
}
if ( !found ) ++i;
}
if ( found )
{
p = malloc( n1 - i + 1 );
if ( p != NULL )
{
size_t j = 0;
do
{
p[j] = s1[i + j];
} while ( p[j++] != '\0' );
}
}
}
return p;
}

How to write function that return dynamic allocated string?

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

;It shows runtime when i am using an array of pointers to strings,or is it because i cant pass data to a function from array of pointers

#include <stdio.h>
#include <string.h>
//reversal function
void reverseString(char* str)
{
int l, i;
char *begin_ptr, *end_ptr, ch;
l = strlen(str);
begin_ptr = str;
end_ptr = str;
//move the ptr to the final pos
for (i = 0; i < l - 1; i++)
end_ptr++;
//pointer swaping
for (i = 0; i < l / 2; i++)
{
ch = *end_ptr;
*end_ptr = *begin_ptr;
*begin_ptr = ch;
begin_ptr++;
end_ptr--;
}
}
// Driver code
---------------------------------main---------------------------------------------------------------------------------------------------
the function call sends the address of the first string in the array
int main()
{
char *str[ ] = {"To err is human...","But to really mess things up...","One needs to know C!!"};
for(int i=0;i<3;i++)
{
reverseString(str[i]); //funtion call
printf("Reverse of the string: %s\n", str[i]);
}
return 0;
}
You may not modify a string literal. Any attempt to modify a string literal results in undefined behavior.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
You should declare a to-dimensional array like
enum { N = 32 };
char str[][N] =
{
"To err is human...",
"But to really mess things up...",
"One needs to know C!!"
};
Pay attention to that the function revreseString is too complicated. Also it is better when the function returns pointer to the reversed string. The function can be defined the following way using pointers
char * reverseString( char *s )
{
if ( *s )
{
for ( char *p = s, *q = s + strlen( s ); p < --q; ++p )
{
char c = *p;
*p = *q;
*q = c;
}
}
return s;
}
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
char * reverseString( char *s )
{
if ( *s )
{
for ( char *p = s, *q = s + strlen( s ); p < --q; ++p )
{
char c = *p;
*p = *q;
*q = c;
}
}
return s;
}
int main(void)
{
enum { N = 32 };
char s[][N] =
{
"To err is human...",
"But to really mess things up...",
"One needs to know C!!"
};
for ( size_t i = 0; i < sizeof( s ) / sizeof( *s ); i++ )
{
puts( reverseString( s[i] ) );
}
return 0;
}
The program output is
...namuh si rre oT
...pu sgniht ssem yllaer ot tuB
!!C wonk ot sdeen enO

Checking a string if it is palindrome or not using pointer

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

Resources