Turning a word into *** symbols - c

So the task is to turn each word in the sentence starting with uppercase into "***".
`
for (i = 1; input[i] != '\0'; i++)
if(isupper(input[i])) input[i] = '***';
printf("\n Changed sentence is: %s", input);
`
This is a code I've written so far. It can change only one character but I don't know how to do it with he whole word.

I assume input is a properly allocated, null terminated C string.
You scan (within the loop) one character at a time; similarly you can change one character at a time.
So you need an additional variable where you store if the word parsed should be converted to a sequence of asterisks.
As you encounter a uppercase letter at the beginning of a word the variable is set to true.
As you encounter the end of the current word (a whitespace) you reset the variable to false.
Finally you change (or not) the current character accordingly.
See the comments in the code
// you need a variable to record if the current word
// should be converted to a sequence of '*'
bool toAsterisk = false;
// sentence scanning loop (one character at a time)
// note that index starts at 0 (not 1)
for (i = 0; input[i] != '\0'; i++)
{
// check if the current word should be converted to asterisks
if( isupper( input[i] ) && toAsterisk == false )
{
toAsterisk = true;
}
// check if you rwach the end of the current word
if( input[i] == ' ' )
{
toAsterisk = true;
}
// convert to asterisks?
if( toAsterisk )
{
input[ i ] = '*';
}
}

The following is a potential solution:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
char input[] = "The Mississippi river is very Wide.";
printf("%s\n", input);
for(int i = 0; i < strlen(input); i++)
{
if((i != 0) && isupper(input[i]))
{
printf("*** ");
while(input[i] != ' ')
i++;
}
else
{
printf("%c", input[i]);
}
}
if(ispunct(input[strlen(input) - 1]))
printf("\b%c\n", input[strlen(input) - 1]);
else
printf("\n");
return 0;
}
Output
$ gcc main.c -o main.exe; ./main.exe
The Mississippi river is very Wide.
The *** river is very ***.

Read through the line.
If character is capitalized, enter while loop until you get a space or end of line and replacing characters with *.
Print the line.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main()
{
char line[1024] = "This should Replace capitalized Words!";
int i = 0;
printf("line: %s\n", line);
for (i = 0; i < strlen(line); i++) {
if (isupper(line[i])) {
while (line[i] != ' ' && line[i] != '\0' && isalpha(line[i])) {
line[i] = '*';
i++;
}
}
}
printf("line: %s\n", line);
return 0;
}
Outputs
$ gcc -Wall -Werror test.c -o t
line: This should Replace capitalized Words!
line: **** should ******* capitalized *****!

Well, following the feedback seen in the comments, here is my version that doesn't depend on the input line length or memory available to the program. It implements a finite state automaton, three states, to detect first letter, next letters and nonword letters. Following a possible implementation:
#include <stdio.h>
#include <ctype.h>
#define IDLE (0)
#define FIRST (1)
#define NEXT (2)
int main()
{
int status = IDLE;
int c;
while ((c = getchar()) != EOF) {
if (isupper(c)) {
switch (status) {
case IDLE:
status = FIRST;
printf("***");
break;
case FIRST: case NEXT:
status = NEXT;
break;
} /* switch */
} else if (islower(c)) {
switch (status) {
case IDLE:
putchar(c);
break;
case FIRST: case NEXT:
status = NEXT;
} /* switch */
} else {
switch (status) {
case IDLE:
putchar(c);
break;
case FIRST: case NEXT:
putchar(c);
status = IDLE;
break;
} /* switch */
} /* if */
} /* while */
} /* main */

By changing one character to three (you change them to three stars) you change length of string. Try starting from there. [This issue may affect the way loop should work]

Related

Prints new line after '\0' character in C

I'm currently doing an assignment where we are to recreate three switches of the cat command, -n/-T/-E. We are to compile and enter in two parameters, the switch and the file name. I store the textfile contents into a buffer.
int main(int argc, char *argv[]){
int index = 0;
int number = 1;
int fd, n, e, t;
n = e = t = 0;
char command[5];
char buffer[BUFFERSIZE];
strcpy(command, argv[1]);
fd = open(argv[2], O_RDONLY);
if( fd == -1)
{
perror(argv[2]);
exit(1);
}
read(fd, buffer,BUFFERSIZE);
if( !strcmp("cat", command)){
printf("%s\n", buffer);
}
else if( !strcmp("-n", command)){
n = 1;
}
else if( !strcmp("-E", command)){
e = 1;
}
else if( !strcmp("-T", command)){
t = 1;
}
else if( !strcmp("-nE", command) || !strcmp("-En", command)){
n = e = 1;
}
else if( !strcmp("-nT", command) || !strcmp("-Tn", command)){
n = t = 1;
}
else if( !strcmp("-ET", command) || !strcmp("-TE", command)){
t = e = 1;
}
else if( !strcmp("-nET", command) || !strcmp("-nTE", command) ||
!strcmp("-TnE", command) || !strcmp("-EnT", command) ||
!strcmp("-ETn", command) || !strcmp("-TEn", command)){
n = e = t = 1;
}
else{
printf("Invalid Switch Entry");
}
if(n){
printf("%d ", number++);
}
while(buffer[index++] != '\0' && ( n || e || t)){
if(buffer[index] == '\n' && e && n){
printf("$\n%d ", number++);
}
else if(buffer[index] == '\n' && e){
printf("$\n");
}
else if(buffer[index] == '\t' && t){
printf("^I");
}
else if(buffer[index] == '\n' && n){
printf("\n%d ", number++);
}
else {
printf("%c", buffer[index]);
}
}
printf("\n");
close(fd);
return 0;
}
Everything works perfectly except when I try to use the -n command. It adds an extra new line. I use a textfile that has
hello
hello
hello world!
instead of
1 hello
2 hello
3 hello world!
it will print out this:
1 hello
2 hello
3 hello world!
4
For some reason it adds the extra line after the world!
Am I missing something simple?
This might not fix your problem, but I don't see any code to put the terminating null character in buffer. Try:
// Reserve one character for the null terminator.
ssize_t n = read(fd, buffer, BUFFERSIZE-1);
if ( n == -1 )
{
// Deal with error.
printf("Unable to read the contents of the file.\n");
exit(1); //???
}
buffer[n] = '\0';
The three cat options that you implement have different "modes":
-T replaces a character (no tab is written);
-E prepends a character with additional output (the new-line character is still written);
-n prepends each line with additional output.
You can handle the first two modes directly. The third mode requires information from the character before: A new line starts at the start of the file and after a new-line character has been read. So you need a flag to keep track of that.
(Your code prints a line number after a new-line character is found. That means that you have to treat the first line explicitly and that you get one too many line umber at the end. After all, a file with n lines has n new-line characters and you print n + 1 line numbers.)
Other issues:
As R Sahu has pointed out, your input isn't null-terminated. You don't really need a null terminator here: read returns the number of bytes read or an error code. You can use that number as limit for index.
You incmenet index in the while condition, which means that you look at the character after the one you checked inside the loop, which might well be the null character. You will also miss the first character in the file.
In fact, you don't need a buffer here. When the file is larger than you buffer, you truncate it. You could call read in a loop until you read fewer bytes than BUFFERSIZE, but the simplest way in this case is to read one byte after the other and process it.
You use too many compound conditions. This isn't wrong per se, but it makes for complicated code. Your main loop reads like a big switch when there are in fact only a few special cases to treat.
The way you determine the flags is both too complicated and too restricted. You chack all combinations of flags, which is 6 for the case that all flags are given. What if you add another flag? Are you going to write 24 more strcmps? Look for the minus sign as first character and then at the letters one by one, setting flags and printing error messages as you go.
You don't need to copy argv[1] to command; you are only inspecting it. And you are introducing a source of error: If the second argument is longer than 4 characters, you will get undefined behaviour, very likely a crash.
If you don't give any options, the file name should be argv[1] instead of argv[2].
Putting this (sans the flag parsing) into practice:
FILE *f = fopen(argv[2], "r");
int newline = 1; // marker for line numbers
// Error checking
for (;;)
{
int c = fgetc(f); // read one character
if (c == EOF) break; // terminate loop on end of file
if (newline) {
if (n) printf("%5d ", number++);
newline = 0;
}
if (c == '\n') {
newline = 1;
if (e) putchar('$');
}
if (c == '\t' && t) {
putchar('^');
putchar('I');
} else {
putchar(c);
}
}
fclose(f);
Edit: If you are restricted to using the Unix open, close and read, you can still use the approach above. You need an additional loop that reads blocks of a certain size with read. The read function returns the value of the bytes read. If that is less than the number of bytes asked for, stop the loop.
The example below adds yet an additional loop that allows to concatenate several files.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define BUFFERSIZE 0x400
int main(int argc, char *argv[])
{
int n = 0;
int e = 0;
int t = 0;
int number = 0;
int first = 1;
while (first < argc && *argv[first] == '-') {
char *str = argv[first] + 1;
while (*str) {
switch (*str) {
case 'n': n = 1; break;
case 'E': e = 1; break;
case 'T': t = 1; break;
default: fprintf(stderr, "Unknown switch -%c.\n", *str);
exit(0);
}
str++;
}
first++;
}
while (first < argc) {
int fd = open(argv[first], O_RDONLY);
int newline = 1;
int bytes;
if (fd == -1) {
fprintf(stderr, "Could not open %s.\n", argv[first]);
exit(1);
}
do {
char buffer[BUFFERSIZE];
int i;
bytes = read(fd, buffer,BUFFERSIZE);
for (i = 0; i < bytes; i++) {
int c = buffer[i];
if (newline) {
if (n) printf("%5d ", number++);
newline = 0;
}
if (c == '\n') {
newline = 1;
if (e) putchar('$');
}
if (c == '\t' && t) {
putchar('^');
putchar('I');
} else {
putchar(c);
}
}
} while (bytes == BUFFERSIZE);
close(fd);
first++;
}
return 0;
}

Printing Garbage [C]

i am having some problems with a buffer. Short story, i have to iterate over the lines in a text file, in which each line has information separated by an empty space, the problem is, the informartion can have an space in it so i wrote a code that check all the empty spaces of a string and checks if its a sperator, and if it is, ut replaces it by a ";".The problem: I write this to another var in where i use malloc to allocate its space, but it ends printing garbage, can somebody point me what's wrong in the code?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
int i;
char *destination;
char* str = "S:15 B:20 B A:15",letra;
destination = (char *)malloc(strlen(str)*sizeof(char));
for (i=0;i<strlen(str);i++){
printf("%c \n",str[i]);
letra = str[i];
if (i == 0){
destination[i] = letra;
}
else if (letra != ' '){
destination[i] = letra;
}
else if (letra == ' ' ){
if (isdigit(str[i-1])){
destination[i] = ";";
}
else{
destination[i] = letra;
}
}
}
printf("%s",destination);
return 0;
}
Here is how I would do it -- a simple, one-directional loop copying just the characters needed, discarding spaces and inserting a ; where necessary.
The space to store a string of length x in (according to strlen) is x+1 -- one extra position for the additional ending zero.
The check of when to insert a ; is easy: after initially skipping spaces (if your input string starts with those) but before any valid text is copied, d will still be 0. If it is not and you encountered a space, then insert a ;.
Only one scenario is not checked here: if the input string ends with one or more spaces, then the final character in destination will also be a ;. It can be trivially discarded by checking just before the Copy loop #3, or just before ending at #4 (and you need to test if d != 0 as well).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main (void)
{
int i, d;
char *destination;
char *str = "S:15 B:20 B A:15";
destination = malloc(strlen(str)+1);
i = 0;
d = 0;
while (str[i])
{
/* 1. Skip spaces at the start */
while (isspace (str[i]))
i++;
/* 2. Do we need to add a ';' here? */
if (d)
{
destination[d] = ';';
d++;
}
/* 3. Copy while not space or -zero- */
while (str[i] && !isspace (str[i]))
{
destination[d] = str[i];
d++;
i++;
}
}
/* 4. Close off. */
destination[d] = 0;
printf ("%s\n", destination);
return 0;
}

Reading a whole line before printing result

Ok firstly I'm a total amateur on programming and i wanted to try something. I want to make a C program which will read a line and then if the characters are accepted to print "ACCEPTED" or "REJECTED" if the characters are valid or not.
So I've used a while loop and some if-else if to add the viable characters. The viable characters are the letters of the alphabet ',' '.' '/' '[' ']'. The problem is that after i type the whole line, it prints ACCEPTED and REJECTED for every character on the line. How can i get the program to read the whole line first and then print the result?
#include <stdio.h>
int main(void) {
char c;
c=getchar();
while(c!=EOF) {
while (c!='\n') {
if (c>='a' && c<='z') {
printf("OK!\n");
}
else if(c==','|| c=='.' ||c=='/') {
printf("OK!\n");
}
else if(c==']'||c=='[') {
printf("OK!\n");
}
else {
printf("ERROR!\n");
}
c=getchar();
}
c=getchar();
}
}
Sorry, my original answer did not seem to relate to your question. Skim reading fail.
Thank you for posting the code, it helps a lot when it comes to answering your question correctly.
Ignoring style for now, I would change your code in this way to make it print OK only when you finish parsing the entire line and it is exactly what #ScottMermelstein said but with code.
#include <stdio.h>
int main(void) {
int c; // This needs to be an int otherwise you won't recognize EOF correctly
int is_ok;
c=getchar();
while(c!=EOF) {
is_ok = 1; // Let's assume all characters will be correct for each line.
while (c!='\n') { // So long as we are in this loop we are on a single line
if (c>='a' && c<='z') {
// Do nothing (leave for clarity for now)
}
else if(c==','|| c=='.' ||c=='/') {
// Do nothing (leave for clarity for now)
}
else if(c==']'||c=='[') {
// Do nothing (leave for clarity for now)
}
else {
is_ok = 0; // Set is_ok to false and get out of the loop
break;
}
c=getchar();
}
if (is_ok) // Only print our result after we finished processing the line.
{
printf("OK!\n");
} else
{
printf("ERROR!\n");
}
c=getchar();
}
return 0; // If you declare main to return int, you should return an int...
}
However, I would recommend modularizing your code a little more. This will come with time and practice but you can write things in a way that is much easier to understand if you hide things away in appropriately named functions.
#include <stdio.h>
int is_valid_char(int c)
{
return (isalpha(c) || c == ',' || c == '.' || c == '/' || c == '[' || c == ']');
}
int main(void) {
int c;
int is_valid_line;
c=getchar();
while(c!=EOF) {
is_valid_line = 1;
while (c!='\n') {
if (!is_valid_char(c)) {
is_valid_line = 0; // Set is_valid_line to false on first invalid char
break; // and get out of the loop
}
c=getchar();
}
if (is_valid_line) // Only print our result after we finished processing the line.
{
printf("OK!\n");
} else
{
printf("ERROR!\n");
}
c=getchar();
}
return 0;
}
You can use scanf and putting a space before the format specifier %c to ignore white-space.
char ch;
scanf(" %c", &ch);
This might be what you are looking for?
Read a line and process good/bad chars and print either OK or Error.
#include <stdio.h>
int main ( void )
{
char buff[1000];
char *p = buff ;
char c ;
int flgError= 0 ; // Assume no errors
gets( buff ) ;
printf("You entered '%s'\n", buff );
while ( *p ) // use pointer to scan through each char of line entered
{
c=*p++ ; // get char and point to next one
if ( // Your OK conditions
(c>='a' && c<='z')
|| (c>='A' && c<='Z') // probably want upper case letter to be OK
|| (c==','|| c=='.' ||c=='/')
|| (c==']'||c=='[')
|| (c=='\n' ) // assume linefeed OK
)
{
// nothing to do since these are OK
}
else
{
printf ("bad char=%c\n",c);
flgError = 1; // 1 or more bad chars
}
}
if ( flgError )
printf ( "Error\n" );
else
printf ( "OK\n" );
}

Removing Characters of a String

I'm trying to write a code that asks the user to enter a string and takes of all characters except the alphabetical.
Now i did it myself and it doesn't seem to work properly. I'm new to strings so i'm trying to understand and master strings. I tried to use gdb on mac but i don't have all the functions to understand this.
Could you please help?
What the code must do: User inputs (for example): h**#el(l)o&^w
and the output is hello.
here is my code:
#include <stdio.h>
#include <string.h>
int main()
{
char string[100];
int i;
int seen = 0;
printf("Enter String: ");
scanf("%s", string);
for (i=0; string[i]!='\0'; i++)
{
if (((string[i]<='a' || string[i]>'z')&&(string[i]<='A' || string[i]>'Z')) ||string[i]!='\0')
{
seen = 1;
}
else
seen = 0;
}
if (seen==0)
{
printf("%s", string);
}
}
well, your code has a couple of important problems:
you're not checking boundaries when iterating… what if I type in a 101 characters string? and a 4242 characters string?
next problem, is that scanf("%s", …) is considered dangerous, for the same reasons
so basically, what you'd want is to use fgets() instead of scanf().
But why not just get the input character by character, and build a string that has only the chars you want? It's simpler and flexible!
basically:
#include <ctype.h>
int main() {
char* string[100];
int i=0;
printf("Enter your string: ");
do {
// getting a character
char c = getchar();
// if the character is alpha
if (isalpha(c) != 0)
// we place the character to the current position and then increment the index
string[i++] = c;
// otherwise if c is a carriage return
else if (c == '\r') {
c = getchar(); // get rid of \n
// we end the string
string[i] = '\0'
}else if (c == '\n')
// we end the string
string[i] = '\0';
// while c is not a carriage return or i is not out of boundaries
} while (c != '\n' || i < 100);
// if we've got to the boundary, replace last character with end of string
if (i == 100)
string[i] = '\0';
// print out!
printf("Here's your stripped string: %s\n", string);
return 0;
}
I did not run it on my computer because it's getting late, so my apologies in case of mistakes.
Addendum:
wee the program skips my statement and shuts down
that's because your condition is inversed, and remove the \0 condition, as it will always happen with the scanf() that always append \0 to the string to end it. Try exchanging seen = 1 and seen = 0 or try using the following condition:
if ((string[i]>='a' && string[i]<='z')||(string[i]>='A' && string[i]<='Z')))
seen = 1;
else
seen = 0;
or simply, use ctypes's isalpha() function, like in our two examples!
No part(remove the extra characters) to change the string in your code.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
char *filter(char *string, int (*test)(int)) {
char *from, *to;
for(to = from = string;*from;++from){
if(test(*from))
*to++ = *from;
}
*to = '\0';
return string;
}
int main(){
char string[100];
printf("Enter String: ");
scanf("%99s", string);
printf("%s\n", filter(string, isalpha));
return 0;
}

C - Integer Input Validation Code

I have the following code in C:
#include "stdafx.h"
#include <stdlib.h>
#include <cstring>
#include <ctype.h>
int main()
{
char buffer[20];
int num;
bool valid = true;
printf("Please enter a number\n");
fgets(buffer, sizeof(buffer), stdin);
printf("\n\n");
if(!isdigit(buffer[0])) //Checking if the first character is -
{
if(buffer[0] != '-')
{
valid = false;
}
else
{
if(!isdigit(buffer[1]))
{
valid = false;
}
}
}
char *pend = strrchr(buffer, '\n'); //Replacing the newline character with '\0'
if (pend != NULL)
{
*pend = '\0';
}
for (int i = 1; i < strlen(buffer); i++) //Checking that each character of the string is numeric
{
if (!isdigit(buffer[i]))
{
valid = false;
break;
}
}
if(valid == false)
{
printf("Invalid input!");
}
else
{
num = atoi(buffer);
printf("The number entered is %d", num);
}
getchar();
}
Basically, the code ensures that the user input is a positive or negative whole number. No letters, floating point numbers etc. are allowed.
The code works perfectly and does its job well.
However, the code is too long and I have to implement it in a number of programs. Is there a simple way to perform all of the above in C? Maybe a shorter alternative that ensures that the input is:
i) not a letter
ii) a positive or negative WHOLE number
bool valid = false;
char *c = buffer;
if(*c == '-'){
++c;
}
do {
valid = true;
if(!isdigit(*c)){
valid = false;
break;
}
++c;
} while(*c != '\0' && *c != '\n');
Note: this will not handle hex values, but will pass octal (integers starting in 0)
I also have to agree that this should be placed in a common library and called as a function.
Although some people have pointed out that strtol may not give you the errors you need, this is a very common type of thing to do, and therefore it does exist in the standard library:
http://www.cplusplus.com/reference/cstdio/sscanf/
#include <stdio.h>
// ....
valid = sscanf (buffer,"%d",&num);
Another comment is that you should not be afraid of writing complicated and useful code, and modularizing it. Create a library for the input parsing routines you find useful!

Resources