#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';
Related
I need to build a function that gets an input and capitalizes only the first letter, doesn't print numbers, capitalizes after a . for a new sentence, and capitalizes all words between a double quotation marks ".
This is what I got until now:
#include <stdio.h>
#define MAX 100
int main()
{
char str[MAX] = { 0 };
int i;
//input string
printf("Enter a string: ");
scanf("%[^\n]s", str); //read string with spaces
//capitalize first character of words
for (i = 0; str[i] != '\0'; i++)
{
//check first character is lowercase alphabet
if (i == 0)
{
if ((str[i] >= 'a' && str[i] <= 'z'))
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
if (str[i] == '.')//check dot
{
//if dot is found, check next character
++i;
//check next character is lowercase alphabet
if (str[i] >= 'a' && str[i] <= 'z')
{
str[i] = str[i] - 32; //subtract 32 to make it capital
continue; //continue to the loop
}
}
else
{
//all other uppercase characters should be in lowercase
if (str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32; //subtract 32 to make it small/lowercase
}
}
printf("Capitalize string is: %s\n", str);
return 0;
}
I cant find a way to remove all numbers from input and convert all lowercase to uppercase inside a " plus code for not printing numbers if user input them.
if I input
I am young. You are young. All of us are young.
"I think we need some help. Please" HELP. NO, NO NO,
I DO NOT
NEED HELP
WHATSOEVER.
"Today’s date is
15/2/2021"...
I am 18 years old, are you 20 years old? Maybe 30 years?
output:
I am young. You are young. All of us are young.
"I THINK WE NEED SOME HELP. PLEASE" help. No, no no,
i do not
need help
whatsoever.
"TODAY’S DATE IS
//"...
I am years old, are you years old? maybe years?
The C standard library provides a set of functions, in ctype.h, that will help you
Of particular interest, would be:
isdigit() - returns true if digit
isalpha() - returns true if alphabet character
isalnum() - returns true if alpha/numeric character
islower() - returns true if lower case character
isupper() - returns true if upper case character
tolower() - converts character to lower case
toupper() - converts character to upper case
So, for example, you could replace the test/modify with:
if ( islower( str[i] ) )
{
str[i] = toupper( str[i] );
}
Pedantically, islower() and toupper() return an unsigned int but that's a separate matter...
You can remove letters from a string if you keep two indices, one for reading and one for writing. The following loop will remove all digits from a string:
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (!isdigit(c)) str[j++] = c;
}
str[j] = '\0';
(I've used to character classification functions from <ctype.h> mentioned in Andrew' answer.)
This is safe, because j will always be smaller or equal to i. Don't forget to mark the end of the filtered string with the nullterminator, '\0'. You can combine this filtering with your already existing code for replacing characters.
In your code, you capitalize letters only if they are directly behind a full stop. That's usually not the case, there's a space between full stop and the next word. It's better to establish a context:
shift: capitalize the next letter (beginning or after full stop.)
lock: capitalize all letters (inside quotation marks.)
When you read a letter, decide whether to capitalize it or not depending of these two states.
Putting the filtering and the "shift context§ together:
#include <stdio.h>
#include <ctype.h>
int main(void)
{
char str[] = "one. two. THREE. 4, 5, 6. \"seven\", eight!";
int shift = 1; // Capitalize next letter
int lock = 0; // Capitalize all letters
int j = 0; // writing index, j <= i
int i; // reading index
for (i = 0; str[i]; i++) {
int c = (unsigned char) str[i];
if (isdigit(c)) continue;
if (isalpha(c)) {
if (shift || lock) {
str[j++] = toupper(c);
shift = 0;
} else {
str[j++] = tolower(c);
}
} else {
if (c == '"') lock = !lock;
if (c == '.') shift = 1;
str[j++] = c;
}
}
str[j] = '\0';
puts(str);
printf("(length: %d)\n", j);
return 0;
}
In order to remove some characters, you should use 2 index variables: one for reading and one for writing back to the same array.
If you are allowed to use <ctype.h>, it is a much more portable and efficient way to test character types.
Also do not use scanf() with protection against buffer overflow. It is as bad as using gets(). Given the difficulty in specifying the maximum number of bytes to store into str, you should use fgets() instead of scanf().
Here is a modified version:
#include <ctype.h>
#include <stdio.h>
#define MAX 100
int main() {
char str[MAX];
int i, j;
unsigned char last, inquote;
//input string
printf("Enter a string: ");
if (!fgets(str, sizeof str, stdin)) { //read string with spaces
// empty file
return 1;
}
last = '.'; // force conversion of first character
inquote = 0;
//capitalize first character of words
for (i = j = 0; str[i] != '\0'; i++) {
unsigned char c = str[i];
//discard digits
if (isdigit(c)) {
continue;
}
//handle double quotes:
if (c == '"') {
inquote ^= 1;
}
//upper case letters after . and inside double quotes
if (last == '.' || inquote) {
str[j++] = toupper(c);
} else {
str[j++] = tolower(c);
}
if (!isspace(c) && c != '"') {
// ignore spaces and quotes for the dot rule
last = c;
}
}
str[j] = '\0'; // set the null terminator in case characters were removed
printf("Capitalized string is: %s", str);
return 0;
}
I have built a function with the goal of taking text that is fed from elsewhere in the program and removing all whitespace and punctuation from it. I'm able to remove whitespace and punctuation, but the changes don't stay after they are made. For instance, I put the character array/string into a for-loop to remove whitespace and verify that the whitespace is removed by printing the current string to the screen. When I send the string through a loop to remove punctuation, though, it acts as though I did not remove whitespace from earlier. This is an example of what I'm talking about:
Example of output to screen
The function that I'm using is here.
//eliminates all punctuation, capital letters, and whitespace in plaintext
char *formatPlainText(char *plainText) {
int length = strlen(plainText);
//turn capital letters into lower case letters
for (int i = 0; i < length; i++)
plainText[i] = tolower(plainText[i]);
//remove whitespace
for (int i = 0; i < length; i++) {
if (plainText[i] == ' ')
plainText[i] = plainText[i++];
printf("%c", plainText[i]);
}
printf("\n\n");
//remove punctuation from text
for (int i = 0; i < length; i++) {
if (ispunct(plainText[i]))
plainText[i] = plainText[i++];
printf("%c", plainText[i]);
}
}
Any help as to why the text is unchanged after if exits the loop would be appreciated.
Those for loops are not necessary. Your function can be modified as follows and I commented where I made those changes:
char* formatPlainText(char *plainText)
{
char *dest = plainText; //dest to hold the modified version of plainText
while ( *plainText ) // as far as *plainText is not '\0'
{
int k = tolower(*plainText);
if( !ispunct(k) && k != ' ') // check each char for ' ' and any punctuation mark
*dest++ = tolower(*plainText); // place the lower case of *plainText to *dest and increment dest
plainText++;
}
*dest = '\0'; // This is important because in the while loop we escape it
return dest;
}
From main:
int main( void ){
char str[] = "Practice ????? &&!!! makes ??progress!!!!!";
char * res = formatPlainText(str);
printf("%s \n", str);
}
The code does convert the string to lower case, but the space and punctuation removal phases are broken: plainText[i] = plainText[i++]; has undefined behavior because you use i and modify it elsewhere in the same expression.
Furthermore, you do not return plainText from the function. Depending on how you use the function, this leads to undefined behavior if you store the return value to a pointer and later dereference it.
You can fix the problems by using 2 different index variables for reading and writing to the string when removing characters.
Note too that you should not use a length variable as the string length changes in the second and third phase. Texting for the null terminator is simpler.
Also note that tolower() and ispunct() and other functions from <ctype.h> are only defined for argument values in the range 0..UCHAR_MAX and the special negative value EOF. char arguments must be cast as (unsigned char) to avoid undefined behavior on negative char values on platforms where char is signed by default.
Here is a modified version:
#include <ctype.h>
//eliminate all punctuation, capital letters, and whitespace in plaintext
char *formatPlainText(char *plainText) {
size_t i, j;
//turn capital letters into lower case letters
for (i = 0; plainText[i] != '\0'; i++) {
plainText[i] = tolower((unsigned char)plainText[i]);
}
printf("lowercase: %s\n", plainText);
//remove whitespace
for (i = j = 0; plainText[i] != '\0'; i++) {
if (plainText[i] != ' ')
plainText[j++] = plainText[i];
}
plainText[j] = '\0';
printf("no white space: %s\n", plainText);
//remove punctuation from text
for (i = j = 0; plainText[i] != '\0'; i++) {
if (!ispunct((unsigned char)plainText[i]))
plainText[j++] = plainText[i];
}
plainText[j] = '\0';
printf("no punctuation: %s\n", plainText);
return plainText;
}
How would you be able to count word lengths and output their occurrences from a string using gets() or fgets()? For example, here is code doing so but using getchar()below. I think writing it in gets() would make it easier to incorporate all of the delimiters in the program rather than having to manually set if statements for each one of those would it not?
#include <string.h>
#include <ctype.h>
const char delim[] = ", . - !*()&^%$##<> ? []{}\\ / \"";
#define SIZE 100
int main(void){
int length[SIZE] = { 0 };
int name[SIZE];
int i = 0, ch, word_len = 0;
int count = 0;
printf("enter sentence: ");
while (1){
ch = getchar();
if (isalpha(ch)){
++word_len;
}
else if (ch == ' ' || ch == '.'){
if (word_len)
length[word_len - 1]++;//-1: to 0 origin
if (ch == '.')
break;
word_len = 0;
}
}
printf("Word Length \tCount \n");
for (i = 0; i<sizeof(length) / sizeof(*length); ++i){
if (length[i])
printf(" %d \t\t%d\n", i + 1, length[i]);
}
return 0;
}
You can build your custom delimiter detection function.
// globals
const char *delim = " .,;:!?\n\0";
const int n_delim = 9;
int is_delim(int c)
{
register int i;
for (i = 0; i < n_delim; i++)
if (c == delim[i]) return 1;
return 0;
}
This function will return 1 every time it can match c with delim. So you can use it like this:
fgets(buffer, 200, stdin);
for (i = 0; i < strlen(buffer); i++) {
if (is_delim(buffer[i])) {
wl[words++] = length;
length = 0;
continue;
}
length++;
}
I'm assuming you're familiar with the fgets function.
You basically will loop through your buffer, making comparisons with each character. Every loop iteration you check if the current character is a word delimiter, if it is, you save the current length and set length=0 for a new word, and at every iteration you increment the length.
You'll need to come up with a way of either not inserting the zero length values due to double delimiters or just ignore them when you're printing the results.
Basically you want to split a string into words, based on some delimiters, and compute their length. The C standard library provides the strtok function, which does exactly what you need: it splits the given string into multiple tokens.
I'm creating my own toUpper function in C, but keep getting a segmentation fault every time I attempt to run it. Can anyone provide me with any hints as to how to fix this problem?
int toUpper(char *str)
{
int i;
for(i=0;i< i <= strlen(str); i++) {
if(str[i] >= 97 && str[i] <= 122) {
str[i] = str[i] -32;
}
}
return(str[i]);
}
int main()
{
char string[20];
printf("Enter any string:\n");
scanf("%s", string);
char result= (char)(toUpper(string));
printf("The string in upper case is:%s\n", result);
}
You're running off the end of the string:
for(i=0;i< i <= strlen(str); i++) {
^--
e.g. a 10 char string has characters 0->9, but you're looping 0->10. Change <= to < so you stop at 9.
Plus, you haven't set any limit on your scanf, so if someone enters a 21 char string, you'll exceed the storage you've allocated the string array.
Recommend changing toUpper() to:
char *toUpper(char *str) {
size_t len = strlen(str);
size_t i;
for (i = 0; i < len; i++) {
if (str[i] >= 'a' && str[i] <= 'z') {
str[i] = str[i] - 'a' + 'A';
}
}
return str;
}
Use correct index range i < strlen(str) vs. i <= strlen(str). This is the main issue. #Marc B
Change return type. Suggested by #Weather Vane. like strcpy(), strcat()
Calculate string length once, rather than many times.
Use literals that match your goal: 'a' instead of 97. #marsh
Use size_t for index and length. That is the type return by strlen() and is the best type to use for array access. Makes a difference with huge strings, but not with these simple examples.
This code does depend on ASCII. This is often OK, but not completely portable.
Change 32 to -'a' + 'A' per #user295691
printf("The string in upper case is:%s\n", result);
result should be a char * but is a char. This is probably where your seg fault is happening. Other places include:
scanf("%s", string);
if the inputted string is longer than 19 chars, you could have problems due to string only being 20 chars long
for(i=0;i< i <= strlen(str); i++) {
if str for whatever reason doesn't have an ending 0, you could seg fault there as well.
Another major issue in the code is the for loop statement.
for(i=0;i< i <= strlen(str); i++)
^ ^
It's probably a typo, but the i < i < wont work.
I created a program that asks the user for a word and then it arranges the letters in that word in alphabetical order and stores it in another string.
#include <stdio.h>
main()
{
char in[100],out[100],ch;
int i,len,j=0;
//ask user for a word
printf("Enter a word: ");
scanf("%s",in);
//arrange that word in alphabetical order
for(ch = 'a'; ch <= 'z'; ++ch)
for(i = 0; i < strlen(in); ++i)
if(in[i] == ch)
{
out[j] = ch;
++j;
}
//print the word
printf("%s",out);
fflush(stdin);
getchar();
}
The problem is when word is stored in the other string, there are some extra letters or symbols after that word. Can someone please tell me what could be possibly wrong with my code?
You're not null terminating the output string. printf("%s",out); will keep outputting characters until it finds 0 ('\0'). There are many options to fix this:
terminate the output to the current iterator position after the for-loop:
out[j] = '\0';
make the output the same length as the input:
out[strlen(in)] = '\0';
declare a 0-initialized array:
char out[100] = { 0 };
fill the output array with zero's yourself:
memset(out, 0; sizeof(out));
...
As the sorting is concerned, if it's just for learning then it's fine, otherwise you should pick a more efficient sorting algorithm
C strings are null terminated
Use
out[j] ='\0';
before printf
The %s specifier searches for a null termination.
In your case it keeps on printing until it finds one, so you get some random symbols.
Also avoid use of fflush.
You might want to update your logic to sort uppercase characters too.
You might want to use a sort say bubble sort
l=strlen(in);
for(i = 0; i < l; i++)
{
for(j = i + 1; j < l - 1; j++)
if(in[j-1] > in[j]){
ch = in[j];
in[j] = in[j-1];
in[j-1] = ch;
}
}
printf("Sorted String :%s",in);