About Rot13-Implementation - c

I am trying to implement the rot13-algorithm in C.
But since I am not very familiar with that language, I have some problems with my code right here.
Basically, I want to rotate every letter in args[] to 13 positions up.
But this code seems to be pretty sluggish:
#include <stdio.h>
char[] rotate(char c[]) {
char single;
int i;
int alen = sizeof(c)/sizeof(c[0]);
char out[alen];
for(i=0;i<=alen;i+=1) {
if(c[i]>='a' && (c[i]+13)<='z'){
out[i] = c[i]+13;
}
}
return out;
}
int main(int argc, char *argv[]) {
printf("The given args will be rotated\n");
int i;
char rotated[sizeof(argv)/sizeof(argv[0])];
rotated = rotate(argv);
/* printing rotated[] later on */
return 0;
}
I know there a lot of holes here - could you show me how to fix this?

Thanks a lot guys, I solved the problem with this code
#include <stdio.h>
int rot13(int c){
if('a' <= c && c <= 'z'){
return rot13b(c,'a');
} else if ('A' <= c && c <= 'Z') {
return rot13b(c, 'A');
} else {
return c;
}
}
int rot13b(int c, int basis){
c = (((c-basis)+13)%26)+basis;
return c;
}
int main() {
printf("The given args will be rotated");
int c;
while((c = getchar()) != EOF){
c = rot13(c);
putchar(c);
}
return 0;
}

How #Michael said this char out[alen] is not accepted by the compiler because you can't declare an array size with a non constant value. Another problem of your code is the for loop for( i = 0; i < = alen; i+=1 ) the arrays start on 0 so if you do the for until the lenght's position you will be out of the array.
About the code:
You must use a pointer to the start of the string as argument of the function, because You can't return arrays in C (But you can return pointers ).
Your if( str[i] >= 'a' && (str[i]+13) <='z') is incorrect because you will convert some letters into symbols take a look.
________
--------------------------!
void rotate( char * str )
{
int i = 0;
/* You do this until you find a '\0' */
for( i = 0; str[ i ] != '\0' ; i++ ){
/* Use the pointer notation if you passed a pointer. */
/* If the letter is between a and m you can simply sum it. */
if( *( str + i ) >= 'a' && *( str + i ) < 'n')
*( str + i ) += 13;
/* If the letter is between the n and z you have to do the opposite.*/
else if( *( str + i ) >= 'n' && *( str + i ) <= 'z')
*( str + i ) -= 13;
}
}

Size of arrays in C must be set at compile time, so you can't use non constant expression for array size.
Consider the below implementation:
// in place rotate
void rotate(char *str)
// str must be a zero-terminated string
{
int i =0;
// loop until str itself is not NULL and str[i] is not zero
for(i=0;str && str[i]; ++i) // ++i is a pre-increment
{
if(str[i] >= 'a' && (str[i]+13) <='z')
{
str[i] = str[i]+13; // modifying str in place
}
}
}
Then your main() can look like this:
int main(int argc, char *argv[])
{
printf("The given args will be rotated: %s\n", argv[1]);
rotate(argv[1]);
printf("Rotated: %s\n", argv[1]);
return 0;
}
Update More advanced version of the transform that takes care of case when str[i] + 13 > 'z'
for(i=0;str && str[i]; ++i) // ++i is a pre-increment
{
// ignore out of range chars
if (str[i] < 'a' || str[i] > 'z') continue;
// rotate
for (off = 13; off > ('z' - str[i]); )
{
off-= (1 + 'z' - str[i]);
str[i] = 'a';
}
str[i]+=off;
}

This function can encode/decode to/from rot13 string. It's compatible with VIM's g? rot13 encoder.
void rot13 (char *s) {
if (s == NULL)
return;
int i;
for (i = 0; s[i]; i++) {
if (s[i] >= 'a' && s[i] <= 'm') { s[i] += 13; continue; }
if (s[i] >= 'A' && s[i] <= 'M') { s[i] += 13; continue; }
if (s[i] >= 'n' && s[i] <= 'z') { s[i] -= 13; continue; }
if (s[i] >= 'N' && s[i] <= 'Z') { s[i] -= 13; continue; }
}
}

Related

Capitalize every word in a string when there are multiple white spaces

I am trying to capitalize every word in and here is my code:
char *cap_string(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0)
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
continue;
}
if (str[i] == ' ')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] -= 32;
continue;
}
}
else
{
if (str[i] == '.')
{
++i;
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] -= 32;
continue;
}
}
}
}
return (str);
}
My question is that my code works fine in most cases, but does not function properly if it encounters multiple white spaces. How can I capitalize a word preceded by multiple white spaces?
Change your code to the following:-
char *cap_string(char *str)
{
int i;
for (i = 0; str[i] != '\0'; i++)
{
if (i == 0 || str[i - 1] == ' ' || str[i - 1] == '.' || str[i-1] == '\n')
{
if (str[i] >= 'a' && str[i] <= 'z')
str[i] -= 32;
}
}
return (str);
}
Testing all cases, using the following code,
#include <stdio.h>
int main()
{
char str[] = "hello world.hello";
printf("%s", cap_string(str));
return 0;
}
returns
Hello World.Hello
I have tried to keep your logic intact and not use any string.h library functions.
You have to keep in mind that the other conditions after the || operator are not checked if the first condition is evaluated as true. So str[-1] never occurs.
The main idea is look at the previous letter to see if the current letter has to upper case. Introduced a constant UPCASE_AFTER so it's easy to add other punctuation marks (say, '!', '?'). Added test case. Refactored for readability.
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#define UPCASE_AFTER " ."
char *cap_string(char *str) {
for (int i = 0; str[i]; i++) {
if (!i || strchr(UPCASE_AFTER, str[i-1])) {
str[i] = toupper(str[i]);
}
}
return str;
}
int main() {
printf("%s\n", cap_string((char []) {"a bb c.d.ee..f."}));
return 0;
}
and it returns:
A Bb C.D.Ee..F.
Here's another alternative:
#include <stdio.h>
// Use standard library routines
// like 'isalpha()', 'toupper'...
// Not all character sets have ASCII's contiguous alphabets.
#include <ctype.h>
char *cap_string( char *str ) {
bool flag = true; // 'state flag' indicating "hunting for lowercase letter"
for( char *cp = str; *cp; cp++ )
if( flag && islower( *cp ) ) {
*cp = (char)toupper( *cp );
flag = false;
}
else
flag = !isalpha( *cp );
return str; // 'return' is not a function call
}
int my_main() {
char str[] = "what? now is the time (we say sometimes) to learn C.";
printf( "%s\n", cap_string( str ) );
return 0; // 'return' is not a function call
}
Output
What? Now Is The Time (We Say Sometimes) To Learn C.

Palindrome/mini-Palindrome in string

I need to check if a given string is a Palindrome or mini-Palindrome.
Palindrome length will be 2 or more, the function need to ignore spaces and ignore the differences of upper and lower alphabet.
if the string is Palindrome the function will transfer the indexes of the start and the end of him and will return 1 else return 0.
example1: "My gym" the function will transfer low=0 high=5 and 1
example2: "I Love ANNA" the function will transfer low=7 high=10 and 1
example3: "I love Pasta" return 0.
Also i can’t use functions from librarys other then string.h stdlib.h stdio.h.
I tried to write like this:
int i;
int size = strlen(str);
i = 0;
while (str[i] != '\0')
{
if (str[i] == ' ')
{
i++;
continue;
}
//-------------------
if (str[i] >= ‘a’ && str[i] <= ‘z’)
str[i] = str[i] - 32;
if (str[size-1] >= ‘a’ && str[size-1] <= ‘z’)
str[size-1] = str[size-1] - 32;
//-------------------
if (str[i] == str[size-1])
{
*low = i;
*high = size-1;
return 1;
}
else
{
size--;
i++;
}
}
return 0;
But it isnt working well, i cant figure how to do it with the example 2
Here goes. Will this help you
#define LOWER(a) (((a) >=' A' && (a) <= 'Z') ? ((a) - 'A' +'a') : (a))
#define MYCMP(a,b) (LOWER(a) == LOWER(b))
int is_palidrome(char *s) {
int start = 0;
int end = strlen(s) - 1;
for (; s[start] // Not end of line
&& end >=0 // Not run over the from of the line
&& start < end // Still not got to the middle
&& MYCMP(s[start], s[end]) == 1; // They are still equal
start++, end--) { //Nowt }
};
return (start >= end);
}
I made a program. It works only if the string contains letters and spaces. You can modify it to work for other characters.
#include <stdio.h>
#include <string.h>
#define SIZE 100
int isPalindrome( char *s, size_t l );
int main() {
char str[SIZE];
size_t i, j, len, pldrm = 0;
fgets(str, SIZE, stdin);
len = strlen(str);
for(i = 0; i < len; i++) if( str[i] != ' ' && !((str[i] >= 'a' && str[i] <= 'z') || (str[i] >= 'A' && str[i] <= 'Z')) ) goto the_end;
for(i = 0; i < len-1; i++) {
if( str[i] != ' ' ) {
for(j = i+1; j < len; j++) {
if( (pldrm = isPalindrome(&str[i], j-i+1)) ) {
str[j+1] = '\0';
goto the_end;
}
}
}
}
the_end:
pldrm ? printf("A palindrome has been found from the position %zu till the position %zu.\n\nThe palindrome is: %s\n", i, j, &str[i]) : puts("No palindromes");
return 0;
}
int isPalindrome( char *s, size_t l )
{
static const char az[26] = "abcdefghijklmnopqrstuvwxyz", AZ[26] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int isPldrm = 1, spc = 0; // used to skip spaces within the palindrome
for(size_t i = 0; i < l/2; i++) {
for(size_t j = 0; j < 26; j++) {
if( s[i] == az[j] || s[i] == AZ[j] ) {
while( s[l-1-i-spc] == ' ' ) ++spc;
if( s[l-1-i-spc] != az[j] && s[l-1-i-spc] != AZ[j] ) {
isPldrm = 0;
goto thats_it;
}
break;
}
}
}
thats_it:
return isPldrm;
}
Also, it finds only the first palindrome in the input. Doesn't check for further palindromes.

C language - return a value from function as function parameter

I have a problem with my homework. I need to count quantity of upper case and quantity of vowels in string. Unfortunately, it always returns number 0 which looks as it doesn't change in function. Everything works until this one.
Here is my code:
#include <stdio.h>
#include <conio.h>
#include <string.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[40];
int upper, chars;
puts("Type a string");
gets(text);
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white spece to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d", chars);
getch();
return 0;
}
char *StringChange(char *text, int *upper, int *chars) {
int i, length;
length = strlen(text);
for (i = 1; i <= length; i++) {
if (text[i - 1] == '*' && (text[i] >= 'a' && text[i] <= 'z')) {
text[i] = text[i] - 32;
}
if (text[i] == ' ') {
text[i] = '*';
}
if (text[i] >= 'A' && text[i] <= 'Z') {
*upper = *upper + 1;
/* *upper++; that also doesn't work */
}
if (text[i] == 'a' || text[i] == 'e' || text[i] == 'i' || text[i] == 'o' || text[i] == 'u' || text[i] == 'y') {
*chars = *chars + 1;
/* *chars++; that also doesn't work */
}
}
if (text[0] >= 'a' && text[0] <= 'z') {
text[0] = text[0] - 32;
}
return (text);
}
I tried your code and I do get non-zero results -- depending on the input, of course, so maybe you are only testing on strings that produce zero.
However, the results are not always correct. There are two problems I found in the code:
1) As pointed out in a comment, you should initialize upper and chars to 0.
2) You are starting the loop at index 1, not index 0. I think you did this so you could look at text[i-1] inside the loop, but it is causing you to exclude the first character from your totals. You should start the loop index and 0 and figure out a different way to handle it within the loop. (Hint - note that the first if within the loop and the one following the loop have similar conditions and the same body.)
There are multiple issues in your code:
you should never use gets().
the variables upper and chars are not initialized
the function StringChange make a special case of text[0] but does not update the counts for this initial byte.
you hard code the conversion of lowercase to uppercase for ASCII.
you should stop at the end of the string
all white space is not replaced, on whitespace followed by a lowercase letter.
uppercase vowels should be counted too.
Here is a modified version:
#include <stdio.h>
char *StringChange(char *text, int *upper, int *chars);
int main(void) {
char text[200];
int upper, vowels;
puts("Type a string");
if (fgets(text, sizeof text, stdin)) {
StringChange(text, &upper, &chars);
puts("Change words to start with upper case and change white space to *");
puts(text);
printf("Quantity of upper case in string: %d\n", upper);
printf("Quantity of vowels: %d\n", vowels);
}
getchar();
return 0;
}
char *StringChange(char *text, int *upper, int *vowels) {
int i, at_start = 1;
*upper = *vowels = 0;
for (i = 0; text[i] != '\0'; i++) {
char c = text[i];
if (at_start && c >= 'a' && c <= 'z') {
c += 'A' - 'a';
text[i] = c;
}
if (c == ' ') {
c = '*';
text[i] = c;
at_start = 1;
} else {
at_start = 0;
}
if (c >= 'A' && c <= 'Z') {
(*upper)++; // *upper++ would just increment the pointer, leading to undefined behavior
}
if (strchr("aeiouyAEIOUY", c) {
(*vowels)++;
}
}
return text;
}

How to Copy the (ASCII) alphabetic characters contained in an existing string into a new one

The new string should contain only the alphabetic characters from the existing string in the same order. Non-alphabetic characters should be not be copied. If s is a null pointer, return a null pointer.
Example input:
"Ready... aim... fire!"
Output:
Readyaimfire
I don't know why in my first for loop, the code never enters the if statement. I'm also not sure if I allocated the memory for the new string correctly. Thanks for any help :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *alphabetic (const char *s);
char *alphabetic (const char *s)
{
char *newChar;
int i;
char n = 0;
long length = strlen(s);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
n++;
}
}
newChar = (char*)malloc(sizeof(char)*n);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
newChar[i] = s[i];
}
}
return newChar;
}
int main (void)
{
char *a, *b, *c;
a = alphabetic ("Ready... aim... fire!");
b = alphabetic ("***");
c = alphabetic ("*a*b*c*");
printf ("%s\n", a);
printf ("%s\n", b);
printf ("%s\n", c);
free(a);
free(b);
free(c);
return 0;
}
The conditional of the first if and the conditional of the second if are such that if one is true then the other is false. Hence, you never get to the line
n++;
You need
if ( (s[i] <= 122 && s[i] >= 97) || (s[i] <= 90 && s[i] >= 65) )
To make the code more readable, you can make it:
if ( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
If you have the option of using the standard library, you can just use:
if ( isalpha(s[i]) )
BTW, the line
s = s + i;
is going to mess things up. As you iterate through the loop, you'll end up skipping parts of the input string. Remove that line.
You Can use a single loop of that
int j = 0; //take integer variable
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
//n++; //Remove this
newChar[j] = s[i];
j++;
}
}
Things about your code:
n should be n+1 to accommodate '\0' character
2nd for loop: you need to have another variable say j =0 and incremented on every match. You can't use i for the newChar array as in the original array s,since i might point to an address that's outof bounds in the newChar array.For ex: ready...aim, newchar # elements 8 while s =11
So saying newChar[8]=s[8] is wrong,rather it should be newChar[5]=s[8].
Posting the corrected code:
char *alphabetic (const char *s)
{
char *newChar;
int i,j=0; //Change1: extra variable j to keep a track of elements for newChar
char n = 0;
long length = strlen(s);
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
n++;
}
}
newChar = (char*)malloc(sizeof(char)*(n+1)); // Change2: n+1 instead of n
for(i=0; i<length; i++)
{
if( (s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z') )
{
newChar[j++] = s[i]; //Change3: j instead of i
}
}
newChar[j]='\0'; //Termination of strings
return newChar;
}
I can't tell you why your code doesn't enter the if statement because you didn't provide the test case (input data) on which the algorithm does not enter the if statement. What I can tell you is that it won't do what you want it to do. Let's break down the for loop for a moment here:
it says "make variable i = 0, then, while i is smaller then the length of char array s, do some stuff then increment i". This is a very handy way to parse a char array. That's just fine and dandy, but inside the for loop, the first instruction is s = s + i. What that will do is move the pointer s forward by i characters at each iteration. Keep in mind that i will increase with time. Say we give that function the char * "This is a sentence.". The function strlen(s) will return 19 (which will be stored in length) and thus the for loop will iterate 19 times, with i taking values from 0 to 18 including. Let's see what's happening to s in there. First time, *s value is T. When you make s = s + i (i = 0), *s will still be T. T's ascii code is 84 and the if checks for values between 97 and 122 (including). So that's that for the first iteration. Then i becomes 1. And s moves one position further, thus *s will be 'h'. The ASCII code for the letter h is 104, so it enters the first if (because it is beween 122 and 97). Then, you ask if s[i] is beween 90 and 65. Now, because you incremented s, *s is 'h', but i == 1 at this point and thus s[i] is actually 'i' (whose ASCII code is 105 and thus never entering that loop). So if you wanna increment your n with your given algorithm I would say you need an input test case looking like so: "ThIsiSaSENtENCE". What you want is a clean string parsing for loop with another clean if to check whether the current character is a letter:
for(i = 0; i < length; i++)
{
if((s[i]<='Z' && s[i] >= 'A') || (s[i]<='z' && s[i]>='a'))
n++;
}
This will count how many letters are there in your char array s.
EDIT:
If you wanna remove those characters which are not letters and return the new string then you might wanna try something like this (NOT OPTIMAL):
char *copyStringByLetter(char *arg, int size)
{
int i = 0;
int n = 0;
for(i = 0; i < size; ++i){
if((s[i]<='z' && s[i]>='a')||(s[i]<='Z' && s[i]>='A'))
n++;
}
char *result = malloc(n+1); //need #include <stdlib.h>
if(!result){
fprintf(stderr, "Error alocating memory!");
exit(EXIT_FAILURE) //you need #include <stdlib.h> for this
}
int j = 0;
for(i = 0; i < size; i++){
if((s[i]<='z' && s[i]>='a')||(s[i]<='Z' && s[i]>='A')){
result[j] = s[i];
j++;
}
}
result[j] = '\0' //terminate the array
return result;
}
If you want to ask me why I am sending the length of char array as an argument, it is to prevent char overruns (who happen more often than you might think)

Need to take multiple digit input from a string removing spaces and alphabets

I am writing a program where I am taking string as an input, here I need to remove spaces , ignore alphabets and use only numerals.
I am able to achieve removing spaces and alphabets, but i can only use single digits and not multiple digits.
Example:Input string:"adsf 12af 1 a123c 53c2m34n"
Here I need to use the input as "12 1 123 54234" required for my application.
It will be great some one could share the logic or the sample code for the same.
Thanks in advance
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int pullOut(const char *str, int array[], int *size){
const char *p = str, *endp;
int pull, count = 0, max = *size, num;
do{
endp=strchr(p, ' ');
if(endp == NULL)
endp=strchr(p, '\0');
for(num=pull=0; p != endp; ++p){
if(isdigit(*p)){
num = num * 10 + *p - '0';
pull = 1;
}
}
if(pull && count < max)
array[count++] = num;
while(*p == ' ')
++p;//skip sapce
}while(*endp != '\0');
return *size = count;
}
int main(void){
char input[] = "adsf 12af 1 a123c 53c2m34n abc def";
int i, arr[128] = { 0 }, arr_num = sizeof(arr)/sizeof(int);
pullOut(input, arr, &arr_num);
for(i = 0; i < arr_num ; ++i)
printf("%d\n", arr[i]);
return 0;
}
int i = 0;int j = 0;
while (input[i])
{
if (input[i] == ' ' || (input[i] >= '0' && input[i] <= '9'))
newString[j++] = input[i];
i++;
}
newString[j] = '\0';
If you do this, you'll copy only numerics and space into newString. I let you do all the memory alloc stuff.
here is your func:
void remove_func(char *str)
{
int i;
i = 0;
while(str[i])
{
if(str[i] >= '0' && str[i] <= '9')
{
putchar(str[i]);
i++;
}
else if(str[i] == ' ' && str[i + 1] != ' ')
{
putchar(str[i]);
i++;
}
else
i++;
}
}
What about this one:
char * getNumbers(const char *src, char *dst)
{
int j=0,i=0;
while (i < strlen(src))
{
if (src[i] >= '0' && src[i] <= '9')
{
dst[j++]=src[i++];
}
else
{
// skip duplicates spaces
if (j > 0 && src[i] == ' ' && dst[j-1] != ',') dst[j++]=',';
i++;
}
}
// remove the trailing ',' if exists
if (j > 0 && dst[j-1] == ',') j--;
dst[j]='\0';
return dst;
}
char src[] = "adsf 12af 1 a123c 53c2m34n";
char dst[sizeof(src)];
getNumbers(src, dst);
printf("'%s' -> '%s'\n", src, dst);
output:
'adsf 12af 1 a123c 53c2m34n' -> '12,1,123,53234'

Resources