Function to allow for only alphabets, hyphens and apostrophes - c

As stated above, I would like to make a function that checks if all the characters in a string contains any prohibited input. The condition is that I only want to accept alphabets, hyphens and apostrophes. Below is my code which does not work the way I intended it to. If it is not an alphabet AND not an apostrophe or a hyphen, I want to change result to 0. However, when I enter a valid input like 'a-a; which is either an alphabet or hyphen, the if function still gets executed which prints "IT IS NOT ACCEPTED".
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int validateInput(char word[]);
int main(void) {
char word[33] = "a-a";
printf("%d",validateInput(word));
}
int validateInput(char word[]) {
int result = 1;
int i;
int length = strlen(word);
for (i = 0; i <length; i++) {
if ((isalpha(word[i]) == 0) && ((word[i] != '-') || (word[i] != '\''))) {
printf("IT IS NOT ACCEPTED\n");
result = 0;
}
else {
printf("ACCEPTED\n");
}
}
return result;
}

There are multiple problems in your code:
you issue the diagnostic at each iteration instead of at the end of the loop
the test (word[i] != '-') || (word[i] != '\'') is always true.
isalpha() should not be passed a char value that could be negative. You should cast the argument as (unsigned char) to avoid potential undefined behavior.
Here is a modified version:
#include <ctype.h>
int validateInput(const char *word) {
int result = 1;
for (size_t i = 0; word[i] != '\0'; i++) {
if (!isalpha((unsigned char)word[i]) && word[i] != '-' && word[i] != '\'') {
result = 0;
break;
}
}
if (result) {
printf("ACCEPTED\n");
} else {
printf("IT IS NOT ACCEPTED\n");
}
return result;
}
Note however that the above function will accept an empty string, which might not be the intended behavior.
Here is a simpler version using sscanf() that works for ASCII:
#include <stdio.h>
int validateInput(const char *word) {
int pos = 0;
sscanf(word, "%*[-a-zA-Z']%n", &pos);
if (pos > 0 && word[pos] == '\0') {
printf("ACCEPTED\n");
return 1;
} else {
printf("IT IS NOT ACCEPTED\n");
return 0;
}
}
And this is a more verbose version using strspn() that works for all encodings:
#include <string.h>
int validateInput(const char *word) {
size_t len = strspn(word, "'-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
if (len > 0 && word[len] == '\0') {
printf("ACCEPTED\n");
return 1;
} else {
printf("IT IS NOT ACCEPTED\n");
return 0;
}
}

Try:
if( !( (isalpha((unsigned char)word[i])) || (word[i] == '-') || (word[i] == '\'')) )

Related

C getchar loop to get integer input from user - [how to improve]

Is there more elegant way to do this task?
Program asks user for integer and repeats if non-digital characters are entered.
To exit loop two conditions expected:
a) all entered characters are digits
b) last character is '\n'
Short solutions like scanf don’t work properly, other approaches require lots of variables loops and if else conditions. User input is common task and I would like to have proper reusable template.
Subjective opinions are appreciated. Way to simplify this function or advice on another solution. Improve formatting. Reading for more systematic understanding.
#include <stdio.h>
int getIntOnly();
int main() {
int x = 0;
x = getIntOnly();
printf("\nvalue entered is: %d \n", x);
}
int getIntOnly() {
int ch, num, quit, abc;
do {
num = 0;
ch = 0;
quit = 0;
abc = 0;
printf("Enter the input: ");
do {
ch = getchar();
if (ch >= 48 && ch <= 57) {
num = num * 10 + (ch - 48);
}
else if (ch == '\n') {
quit = 1;
}
else {
abc = 1;
}
}
while (quit == 0);
}
while (quit == 0 || abc == 1);
return (num);
}
Using fgets() means you'll get the full text at once.
You can then examine it (and convert it too) to suit your needs.
int getIntOnly( void ) {
int value = 0, i = 0;
char buf[ 64 ];
do {
printf( "Enter integer value: " );
fgets( buf, sizeof( buf ), stdin );
value = 0;
for( i = 0; '0' <= buf[i] && buf[i] <= '9'; i++ )
value = value * 10 + buf[i] - '0';
} while( buf[i] != '\n' ); // good! reached end of line
return value;
}
May be better? Add some validity checks for the result of fgets() and strtol() according to your original code.
#include <stdio.h>
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
int getIntOnly();
int main() {
int x = 0;
x = getIntOnly();
printf("\nvalue entered is: %d \n", x);
}
bool isDigit(char ch) {
return (ch >= '0' && ch <= '9')? true : false;
}
bool isAllDigit(char *buf) {
int i;
for (i = 0; buf[i] != '\n'; i++) {
if (isDigit(buf[i]) == false) {
return false;
}
}
return true;
}
bool isVaildInt(long int number) {
return (number >= INT_MIN && number <= INT_MAX)? true : false;
}
int getIntOnly() {
char buf[100];
long int num;
bool done = false;
do {
/* read line-by-line */
fgets(buf, 100, stdin);
if (isAllDigit(buf) == false)
continue;
num = strtol(buf, NULL, 10);
/* strtol() returns long int */
if (isVaildInt(num) == false)
continue;
done = true;
} while (done == false);
return num;
}

Type checking arbitrary length array in ANSI C

Hi I am confined to stdio.h, stdlib.h and string.h and I need to ask a user for input - the input can be any number of characters between 1 and 6, however the first two characters MUST be an uppercase alphabetical letter, and the remaining four characters MUST be a number between 0 and 9.
Examples of valid input:
AB1
AB1234
AB
A
Examples of Invalid Input:
AB12345 (too many characters)
123 (first two characters are not uppercase letters)
ABA (a character after the second one is not a numeric value)
Here is my attempt so far (just bear in mind I have almost no experience with C, the likelihood that this solution is "idiomatic" is next to none, and the reason I am asking this is so that I can learn):
Flightcode is a char array defined as flightcode[7] it lives inside another struct called flight. I am fgetsing it into a temp_array[7] first and then strcpying it into the flight->flightcode such that the null terminator is appended and I don't know a better way of doing that.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FLIGHTCODE_LEN 6
#define MAX_CITYCODE_LEN 3
#define MAX_NUM_FLIGHTS 50
#define DB_NAME "database"
typedef struct {
int month;
int day;
int hour;
int minute;
} date_time_t;
typedef struct {
char flightcode[MAX_FLIGHTCODE_LEN + 1];
date_time_t departure_dt;
char arrival_city[MAX_CITYCODE_LEN + 1];
date_time_t arrival_dt;
} flight_t;
date_time_t departure_dt;
date_time_t arrival_dt;
char * scanline(char *dest, int dest_len);
int main(){
char temp_string[100];
flight_t flight[MAX_NUM_FLIGHTS + 1];
int correct_code = 0;
printf("Enter flight code>\n");
scanline(temp_string, sizeof(flight->flightcode));
strcpy(flight->flightcode, temp_string);
while(correct_code == 0)
{
for(int i = 0; flight->flightcode[i] != '\0' && correct_code == 0; i++)
{
while((i < 2 && (flight->flightcode[i] <= 64 || flight->flightcode[i] >= 91)) || (i > 1 && (flight->flightcode[i] < 48 || flight->flightcode[i] >= 58)))
{
printf("Invalid input.\n");
scanline(temp_string, sizeof(flight->flightcode));
strcpy(flight->flightcode, temp_string);
}
if((i < 2 && (flight->flightcode[i] > 64 || flight->flightcode[i] < 91)) || (i > 1 && (flight->flightcode[i] >= 48 || flight->flightcode[i] < 58)))
{
correct_code = 1;
}
}
}
}
char * scanline(char *dest, int dest_len){
int i, ch;
i = 0;
for (ch = getchar();
ch != '\n' && ch != EOF && i < dest_len -1; ch = getchar())
dest[i++] = ch;
dest[i] = '\0';
while (ch != '\n' && ch != EOF)
ch = getchar();
return (dest);
}
Scansets and the %n specifier could be used to parse the input.
The format string "%n%2[A-Z]%n%4[0-9]%n" uses the %n specifier in three places to capture the number of characters processed. The scanset %2[A-Z] will scan up to two characters if the characters are in the set of upper case letters. %4[0-9] will scan up to four characters if the characters are digits.
If two values are scanned by sscanf, the number of characters processed are subtracted to make sure there are two leading upper case characters and six or fewer total character and the trailing character is the terminating zero.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FLIGHTCODE_LEN 6
#define MAX_CITYCODE_LEN 3
#define MAX_NUM_FLIGHTS 50
#define DB_NAME "database"
typedef struct {
int month;
int day;
int hour;
int minute;
} date_time_t;
typedef struct {
char flightcode[MAX_FLIGHTCODE_LEN + 1];
date_time_t departure_dt;
char arrival_city[MAX_CITYCODE_LEN + 1];
date_time_t arrival_dt;
} flight_t;
date_time_t departure_dt;
date_time_t arrival_dt;
char * scanline(char *dest, int dest_len);
int main(){
int head = 0, leading = 0, tail = 0;
int correct_code = 0;
int result = 0;
char temp_string[100];
char upper[3] = "";
char digits[5] = "";
flight_t flight[MAX_NUM_FLIGHTS + 1];
do {
printf("Enter flight code>\n");
scanline(temp_string, sizeof(temp_string));
if ( 0 < ( result = sscanf ( temp_string, "%n%2[A-Z]%n%4[0-9]%n", &head, upper, &leading, digits, &tail))) {
if ( 1 == result && 0 == temp_string[leading]) {
correct_code = 1;
break;
}
if ( 2 == result && 2 == leading - head && 7 > tail - head && 0 == temp_string[tail]) {
correct_code = 1;
}
else {
printf ( "invalid input\n");
}
}
else {
printf ( "invalid input\n");
}
} while(correct_code == 0);
printf ( "Input is: %s\n", temp_string);
strcpy(flight->flightcode, temp_string);
return 0;
}
char * scanline(char *dest, int dest_len){
int i, ch;
i = 0;
for (ch = getchar(); ch != '\n' && ch != EOF && i < dest_len -1; ch = getchar()) {
dest[i++] = ch;
}
dest[i] = '\0';
while (ch != '\n' && ch != EOF) {
ch = getchar();
}
return dest;
}
Your function scanline does not do much more than the standard function fgets. I propose to use the standard function instead. Removing the trailing newline '\n' is easy.
I have split the checks into 3 parts:
Check the length to be more than 0 and not more than MAX_FLIGHTCODE_LEN.
Check the first 2 characters to be uppercase letters A..Z
Check the remaining characters to be digits 0..9
Proposed code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FLIGHTCODE_LEN 6
#define MAX_CITYCODE_LEN 3
#define MAX_NUM_FLIGHTS 50
#define DB_NAME "database"
typedef struct {
int month;
int day;
int hour;
int minute;
} date_time_t;
typedef struct {
char flightcode[MAX_FLIGHTCODE_LEN + 1];
date_time_t departure_dt;
char arrival_city[MAX_CITYCODE_LEN + 1];
date_time_t arrival_dt;
} flight_t;
date_time_t departure_dt;
date_time_t arrival_dt;
int main(void){
char temp_string[100];
flight_t flight[MAX_NUM_FLIGHTS + 1];
int correct_code;
size_t len;
int i;
do
{
/* we first assume the code is correct and set this to 0 on any error */
correct_code = 1;
printf("Enter flight code>\n");
if(fgets(temp_string, sizeof(temp_string), stdin) == NULL)
{
if(feof(stdin)) fprintf(stderr, "no input (EOF)\n");
else perror("fgets");
correct_code = 0;
temp_string[0] = '\0';
}
if(correct_code)
{
len = strlen(temp_string);
/* cut off newline
* Use a loop to handle CR and LF just in case Windows might leave more than one character */
while((len > 0) &&
((temp_string[len - 1] == '\n') ||
(temp_string[len - 1] == '\r')))
{
len--;
temp_string[len] == '\0';
}
if(len > MAX_FLIGHTCODE_LEN)
{
correct_code = 0;
fprintf(stderr, "Input must not be longer than %d characters.\n", MAX_FLIGHTCODE_LEN);
}
if(len == 0)
{
correct_code = 0;
fprintf(stderr, "Empty input.\n");
}
}
/* check first two letters */
for(i = 0; (i < 2) && (i < len) && correct_code; i++)
{
/* you could use function isupper when you make sure the locale is set to "C" */
if((temp_string[i] < 'A') || (temp_string[i] > 'Z'))
{
correct_code = 0;
fprintf(stderr, "first two characters must be uppercase letters. Found '%c' at position %d\n", temp_string[i], i);
}
}
/* check digits starting from 3rd character */
for(i = 2; (i < MAX_FLIGHTCODE_LEN) && (i < len) && correct_code; i++)
{
/* you could use function isdigit here */
if((temp_string[i] < '0') || (temp_string[i] > '9'))
{
correct_code = 0;
fprintf(stderr, "Third to last characters must be digits. Found '%c' at position %d\n", temp_string[i], i);
}
}
if(correct_code)
{
/* we already checked that length is not more than MAX_FLIGHTCODE_LEN, so we don't need strncpy to avoid buffer overflow */
strcpy(flight->flightcode, temp_string);
printf("Valid code: %s\n", flight->flightcode);
}
else
{
fprintf(stderr, "Invalid code.\n");
}
} while(!correct_code);
return 0;
}
You have a requirement that does not fit well with what scanf can easily do, so I would stay away from it, and use fgets as a primary read utility.
But as the number of acceptable uppercase and digit characters is not fixed by only limited I would use a custom parser based on a state machine. It is probably not the most elegant nor efficient way but it is simple, robust and easy to maintain.
Just to demonstrate it, I have allowed blank characters before the first uppercase one and spaces after the last digit. So the following code accept an arbitrary long line following this regex pattern [ \t]*[A-Z]{1,maxupper}[0-9]{0,maxdigit}\s* provided it receives a buffer of size at least maxupper+maxupper+1. It returns a pointer to the buffer is successful or NULL if not.
As you have said that you could not use the ctype macros, I have defined ASCII (or any charset derived from ASCII) equivalent for the ones I have used.
#define TRUE 1
#define FALSE 0
inline int isupper(int c) {
return c >= 'A' && c <= 'Z'; // only for ASCII and derived
}
inline int isdigit(char c) {
return c >= '0' && c <= '9'; // guarantee per standard
}
inline int isblank(int c) {
return c == ' ' || c == '\t';
}
inline int isspace(int c) {
static const char spaces[] = " \t\r\n\v";
for(const char *s=spaces; *s != '\0'; s++) {
if (c == *s) return TRUE;
}
return FALSE;
}
char *get_string(char *buffer, int maxupper, int maxdigit, FILE *fd) {
char buf[16]; // any size >=2 will fit
char *cur = buffer;
int state = 0, uppersize=0, digitsize=0;
for (;;) { // allow lines longer than buf
if (NULL == fgets(buf, sizeof(buf), fd)) {
*cur = '\0'; // EOF: do not forget the terminating NULL
return state >= 1 ? buffer : NULL; // must have at least 1 char
}
for (char *b=buf; *b!='\0'; b++) {
switch(state) {
case 0: // spaces before first uppercase
if (isblank(*b)) break;
state++;
case 1: // first uppercase
if (! isupper(*b)) {
state = 5; // must read up to \n
break;
}
state++;
case 2: // process uppercase chars
if (! isupper(*b)) {
if (uppersize > 0) state++;
else {
state = 5; // must read up to \n
break;
}
}
else {
if (uppersize >= maxupper) {
state = 5; // must read up to \n
break;
}
*cur++ = *b;
uppersize++;
break;
}
case 3: // process digit chars
if (! isdigit(*b)) {
state++;
}
else {
if (digitsize >= maxdigit) {
state = 5; // must read up to \n
break;
}
*cur++ = *b;
digitsize++;
break;
}
case 4: // allow spaces after last digit
if ('\n' == *b) {
*cur = '\0';
return buffer;
}
if (! isspace(*b)) state++
break;
case 5: // on error clean end of line
if ('\n' == *b) return NULL;
}
}
}
}
Then in your code, you simply calls it that way:
...
printf("Enter flight code>\n");
if (NULL == get_string(flight->flightcode, 2, 4, stdin)) {
// process the error
...
}
...
First thing, realize that your question text is missing a question. Moreover, your question title makes no sense.
Anyway, here it is a possible, purposely very ugly, solution. Approach: you want to do X, so you write the code to do X. Let's start with scanline():
int scanline(char *dest, int dest_len)
{
int i = 0;
int ch;
while (1) {
// Read
ch = fgetc(stdin);
// Check
if (ch == EOF)
break;
if (ch == '\n')
break;
if (i >= dest_len - 1)
break;
// Use
dest[i] = ch;
++i;
}
dest[i] = 0;
// Is the string finished? Ok!
if (ch == '\n' || ch == EOF)
return 1;
// Otherwise discard the rest of the line. Not ok!
while (ch != '\n' && ch != EOF)
ch = fgetc(stdin);
return 0;
}
I know this is ugly, but I believe that it is helpful to clarify the three steps involved in file input: read, check, use. Note that it returns true if the line was up to the required number of characters (one less than the buffer size to accomodate for the terminator.
Then you want to check if:
scanline() is successful
there is at least one character.
character 0 is between 'A' and 'Z'
character 1 is between 'A' and 'Z'
character 2 is between '0' and '1'
character 3 is between '0' and '1'
character 4 is between '0' and '1'
character 5 is between '0' and '1'
Lets write the code for that:
int main(void)
{
flight_t flight;
while (1) {
printf("Enter flight code>\n");
if (!scanline(flight.flightcode, sizeof(flight.flightcode))) {
printf("Too many characters.\n");
continue;
}
int i = 0;
if (flight.flightcode[i] == 0) {
printf("Empty input.\n");
continue;
}
if (flight.flightcode[i] < 'A' || flight.flightcode[i] > 'Z') {
printf("Character %d is not upper case.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < 'A' || flight.flightcode[i] > 'Z') {
printf("Character %d is not upper case.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
if (flight.flightcode[i] < '0' || flight.flightcode[i] > '9') {
printf("Character %d is not a digit.\n", i);
continue;
}
i++;
if (flight.flightcode[i] == 0)
break;
}
}
Some remarks:
in your code you set correct_code to 1 as soon as the first character was ok. If you want to loop through the characters you must check if there is an error and exit the loop.
don't use ASCII codes when you have the specific character literals available.
I suggest that you take my solution and, as an exercise fix it to be able to work with arbitrary MAX_FLIGHTCODE_LEN, and possibly with arbitrary number of letters and numbers. Of course MAX_FLIGHTCODE_LEN shall be equal to their sum!
Drop the useless requirement for not using <ctype.h>, and use also <stdbool.h>, which makes the programmer intention clearer.

Count the number of words using C [duplicate]

I need to write a function that will count words in a string. For the
purpose of this assignment, a "word" is defined to be a sequence
of non-null, non-whitespace characters, separated from other words by
whitespace.
This is what I have so far:
int words(const char sentence[ ]);
int i, length=0, count=0, last=0;
length= strlen(sentence);
for (i=0, i<length, i++)
if (sentence[i] != ' ')
if (last=0)
count++;
else
last=1;
else
last=0;
return count;
I am not sure if it works or not because I can't test it until my whole program is finished and I am not sure it will work, is there a better way of writing this function?
You needed
int words(const char sentence[])
{
}
(note braces).
For loops go with ; instead of ,.
Without any disclaimer, here's what I'd have written:
See it live http://ideone.com/uNgPL
#include <string.h>
#include <stdio.h>
int words(const char sentence[ ])
{
int counted = 0; // result
// state:
const char* it = sentence;
int inword = 0;
do switch(*it) {
case '\0':
case ' ': case '\t': case '\n': case '\r': // TODO others?
if (inword) { inword = 0; counted++; }
break;
default: inword = 1;
} while(*it++);
return counted;
}
int main(int argc, const char *argv[])
{
printf("%d\n", words(""));
printf("%d\n", words("\t"));
printf("%d\n", words(" a castle "));
printf("%d\n", words("my world is a castle"));
}
See the following example, you can follow the approach : count the whitespace between words .
int words(const char *sentence)
{
int count=0,i,len;
char lastC;
len=strlen(sentence);
if(len > 0)
{
lastC = sentence[0];
}
for(i=0; i<=len; i++)
{
if((sentence[i]==' ' || sentence[i]=='\0') && lastC != ' ')
{
count++;
}
lastC = sentence[i];
}
return count;
}
To test :
int main()
{
char str[30] = "a posse ad esse";
printf("Words = %i\n", words(str));
}
Output :
Words = 4
#include <ctype.h> // isspace()
int
nwords(const char *s) {
if (!s) return -1;
int n = 0;
int inword = 0;
for ( ; *s; ++s) {
if (!isspace(*s)) {
if (inword == 0) { // begin word
inword = 1;
++n;
}
}
else if (inword) { // end word
inword = 0;
}
}
return n;
}
bool isWhiteSpace( char c )
{
if( c == ' ' || c == '\t' || c == '\n' )
return true;
return false;
}
int wordCount( char *string )
{
char *s = string;
bool inWord = false;
int i = 0;
while( *s )
{
if( isWhiteSpace(*s))
{
inWord = false;
while( isWhiteSpace(*s) )
s++;
}
else
{
if( !inWord )
{
inWord = true;
i++;
}
s++;
}
}
return i;
}
Here is one of the solutions. It counts words with multiple spaces or just space or space followed by the word.
#include <stdio.h>
int main()
{
char str[80];
int i, w = 0;
printf("Enter a string: ");
scanf("%[^\n]",str);
for (i = 0; str[i] != '\0'; i++)
{
if((str[i]!=' ' && str[i+1]==' ')||(str[i+1]=='\0' && str[i]!=' '))
{
w++;
}
}
printf("The number of words = %d", w );
return 0;
}
I know this is an old thread, but perhaps someone needs a simple solution, just checks for blank space in ascii and compares current char to that while also makign sure first char is not a space, cheers!
int count_words(string text){
int counter = 1;
int len = strlen(text);
for(int i = 0; i < len; i++){
if(text[i] == 32 && i != 0) {
counter++;
}
}
return counter;}
Here is another solution:
#include <string.h>
int words(const char *s)
{
const char *sep = " \t\n\r\v\f";
int word = 0;
size_t len;
s += strspn(s, sep);
while ((len = strcspn(s, sep)) > 0) {
++word;
s += len;
s += strspn(s, sep);
}
return word;
}
#include<stdio.h>
int main()
{
char str[50];
int i, count=1;
printf("Enter a string:\n");
gets(str);
for (i=0; str[i]!='\0'; i++)
{
if(str[i]==' ')
{
count++;
}
}
printf("%i\n",count);
}
#include<stdio.h>
#include<string.h>
int getN(char *);
int main(){
char str[999];
printf("Enter Sentence: "); gets(str);
printf("there are %d words", getN(str));
}
int getN(char *str){
int i = 0, len, count= 0;
len = strlen(str);
if(str[i] >= 'A' && str[i] <= 'z')
count ++;
for (i = 1; i<len; i++)
if((str[i]==' ' || str[i]=='\t' || str[i]=='\n')&& str[i+1] >= 'A' && str[i+1] <= 'z')
count++;
return count;
}
#include <stdio.h>
int wordcount (char *string){
int n = 0;
char *p = string ;
int flag = 0 ;
while(isspace(*p)) p++;
while(*p){
if(!isspace(*p)){
if(flag == 0){
flag = 1 ;
n++;
}
}
else flag = 0;
p++;
}
return n ;
}
int main(int argc, char **argv){
printf("%d\n" , wordcount(" hello world\nNo matter how many newline and spaces"));
return 1 ;
}
I found the posted question after finishing my function for a C class I'm taking. I saw some good ideas from code people have posted above. Here's what I had come up with for an answer. It certainly is not as concise as other's, but it does work. Maybe this will help someone in the future.
My function receives an array of chars in. I then set a pointer to the array to speed up the function if it was scaled up. Next I found the length of the string to loop over. I then use the length of the string as the max for the 'for' loop.
I then check the pointer which is looking at array[0] to see if it is a valid character or punctuation. If pointer is valid then increment to next array index. The word counter is incremented when the first two tests fail. The function then will increment over any number of spaces until the next valid char is found.
The function ends when null '\0' or a new line '\n' character is found. Function will increment count one last time right before it exit to account for the word preceding null or newline. Function returns count to the calling function.
#include <ctype.h>
char wordCount(char array[]) {
char *pointer; //Declare pointer type char
pointer = &array[0]; //Pointer to array
int count; //Holder for word count
count = 0; //Initialize to 0.
long len; //Holder for length of passed sentence
len = strlen(array); //Set len to length of string
for (int i = 0; i < len; i++){
//Is char punctuation?
if (ispunct(*(pointer)) == 1) {
pointer += 1;
continue;
}
//Is the char a valid character?
if (isalpha(*(pointer)) == 1) {
pointer += 1;
continue;
}
//Not a valid char. Increment counter.
count++;
//Look out for those empty spaces. Don't count previous
//word until hitting the end of the spaces.
if (*(pointer) == ' ') {
do {
pointer += 1;
} while (*(pointer) == ' ');
}
//Important, check for end of the string
//or newline characters.
if (*pointer == '\0' || *pointer == '\n') {
count++;
return(count);
}
}
//Redundent return statement.
count++;
return(count);
}
I had this as an assignment...so i know this works.
The function gives you the number of words, average word length, number of lines and number of characters.
To count words, you have to use isspace() to check for whitespaces. if isspace is 0 you know you're not reading whitespace. wordCounter is a just a way to keep track of consecutive letters. Once you get to a whitespace, you reset that counter and increment wordCount. My code below:
Use isspace(c) to
#include <stdio.h>
#include <ctype.h>
int main() {
int lineCount = 0;
double wordCount = 0;
double avgWordLength = 0;
int numLines = 0;
int wordCounter = 0;
double nonSpaceChars = 0;
int numChars = 0;
printf("Please enter text. Use an empty line to stop.\n");
while (1) {
int ic = getchar();
if (ic < 0) //EOF encountered
break;
char c = (char) ic;
if (isspace(c) == 0 ){
wordCounter++;
nonSpaceChars++;
}
if (isspace(c) && wordCounter > 0){
wordCount++;
wordCounter =0;
}
if (c == '\n' && lineCount == 0) //Empty line
{
break;
}
numChars ++;
if (c == '\n') {
numLines ++;
lineCount = 0;
}
else{
lineCount ++;
}
}
avgWordLength = nonSpaceChars/wordCount;
printf("%f\n", nonSpaceChars);
printf("Your text has %d characters and %d lines.\nYour text has %f words, with an average length of %3.2f ", numChars, numLines, wordCount, avgWordLength);
}
Here is one solution. This one will count words correctly even if there are multiple spaces between words, no spaces around interpuncion symbols, etc. For example: I am,My mother is. Elephants ,fly away.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int countWords(char*);
int main() {
char string[1000];
int wordsNum;
printf("Unesi nisku: ");
gets(string); /*dont use this function lightly*/
wordsNum = countWords(string);
printf("Broj reci: %d\n", wordsNum);
return EXIT_SUCCESS;
}
int countWords(char string[]) {
int inWord = 0,
n,
i,
nOfWords = 0;
n = strlen(string);
for (i = 0; i <= n; i++) {
if (isalnum(string[i]))
inWord = 1;
else
if (inWord) {
inWord = 0;
nOfWords++;
}
}
return nOfWords;
}
this is a simpler function to calculate the number of words
int counter_words(char* a){`
// go through chars in a
// if ' ' new word
int words=1;
int i;
for(i=0;i<strlen(a);++i)
{
if(a[i]==' ' && a[i+1] !=0)
{
++words;
}
}
return words;}

Replace space with newline

I'm trying to do a space with line replacer for Ti-89 calculators so that I can print lines without them being cut because of the horizontal character length. They would normally look like so
This is a pretty long test
ing for the Ti89 Calculator
and I would like them to look like so
This is a pretty long
testing for the Ti89
Calculator
I tried to do it with this code
void _print_line(char* string)
{
int k = strlen(string);
if(k > 26)
{
int n = 0;
int c = 25;
while(n == 0)
{
if(string[c] == 32)
{
n = 1;
}
else
{
c--;
}
if(c <= 0)
{
n = 2;
}
}
if(n == 1)
{
string[c] == '\n';
}
}
printf("%s\n", string);
}
But it seems to just ignore it and keep printing it like the first example.
You are not inserting the carriage return.
Replace
string[c] == '\n';
With
string[c] = '\n';
As Till said, you are not inserting the carriage return. The line
string[c] == '\n';
needs to be
string[c] = '\n';
With the difference being one "equals" sign versus two.
The reason is because "==" is a conditional operator which evaluates to either true or false, while "=" is the assignment operator which sets a value to a variable.
There needs to be processed for the entire string.
Keep a record of the current output character position to check whether or not exceed the specified width when you output the next word.
like this:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define DISP_OUT stdout
#define DISP_WIDTH 26
int disp_one(char ch){
static int pos;
fputc(ch, DISP_OUT);
if(ch == '\n')
pos = 0;
else
++pos;
if(pos == DISP_WIDTH){
fputc('\n', DISP_OUT);
pos = 0;
}
return pos;
}
typedef enum word_break {
KEEP, BREAK
} WORD_BREAK;
void disp(const char *str, WORD_BREAK word_break){
static int pos;
switch(word_break){
case BREAK:
while(*str){
pos = disp_one(*str++);
}
break;
case KEEP:
while(*str){
if(isspace((unsigned char)*str)){
pos = disp_one(*str++);
continue;
}
const char *end = str;//end : word end (find delimiter)
while(*end && !isspace((unsigned char)*end))
++end;
int len = end - str;//length of next output word
if(pos + len >= DISP_WIDTH && len < DISP_WIDTH){
pos = disp_one('\n');
}
while(str < end){
pos = disp_one(*str++);
}
}
break;
}
}
int main(void){
char *text = "This is a pretty long testing for the Ti89 Calculator";
disp(text, BREAK);
disp("\n", BREAK);
disp(text, KEEP);
return 0;
}

Counting words in a string - c programming

I need to write a function that will count words in a string. For the
purpose of this assignment, a "word" is defined to be a sequence
of non-null, non-whitespace characters, separated from other words by
whitespace.
This is what I have so far:
int words(const char sentence[ ]);
int i, length=0, count=0, last=0;
length= strlen(sentence);
for (i=0, i<length, i++)
if (sentence[i] != ' ')
if (last=0)
count++;
else
last=1;
else
last=0;
return count;
I am not sure if it works or not because I can't test it until my whole program is finished and I am not sure it will work, is there a better way of writing this function?
You needed
int words(const char sentence[])
{
}
(note braces).
For loops go with ; instead of ,.
Without any disclaimer, here's what I'd have written:
See it live http://ideone.com/uNgPL
#include <string.h>
#include <stdio.h>
int words(const char sentence[ ])
{
int counted = 0; // result
// state:
const char* it = sentence;
int inword = 0;
do switch(*it) {
case '\0':
case ' ': case '\t': case '\n': case '\r': // TODO others?
if (inword) { inword = 0; counted++; }
break;
default: inword = 1;
} while(*it++);
return counted;
}
int main(int argc, const char *argv[])
{
printf("%d\n", words(""));
printf("%d\n", words("\t"));
printf("%d\n", words(" a castle "));
printf("%d\n", words("my world is a castle"));
}
See the following example, you can follow the approach : count the whitespace between words .
int words(const char *sentence)
{
int count=0,i,len;
char lastC;
len=strlen(sentence);
if(len > 0)
{
lastC = sentence[0];
}
for(i=0; i<=len; i++)
{
if((sentence[i]==' ' || sentence[i]=='\0') && lastC != ' ')
{
count++;
}
lastC = sentence[i];
}
return count;
}
To test :
int main()
{
char str[30] = "a posse ad esse";
printf("Words = %i\n", words(str));
}
Output :
Words = 4
#include <ctype.h> // isspace()
int
nwords(const char *s) {
if (!s) return -1;
int n = 0;
int inword = 0;
for ( ; *s; ++s) {
if (!isspace(*s)) {
if (inword == 0) { // begin word
inword = 1;
++n;
}
}
else if (inword) { // end word
inword = 0;
}
}
return n;
}
bool isWhiteSpace( char c )
{
if( c == ' ' || c == '\t' || c == '\n' )
return true;
return false;
}
int wordCount( char *string )
{
char *s = string;
bool inWord = false;
int i = 0;
while( *s )
{
if( isWhiteSpace(*s))
{
inWord = false;
while( isWhiteSpace(*s) )
s++;
}
else
{
if( !inWord )
{
inWord = true;
i++;
}
s++;
}
}
return i;
}
Here is one of the solutions. It counts words with multiple spaces or just space or space followed by the word.
#include <stdio.h>
int main()
{
char str[80];
int i, w = 0;
printf("Enter a string: ");
scanf("%[^\n]",str);
for (i = 0; str[i] != '\0'; i++)
{
if((str[i]!=' ' && str[i+1]==' ')||(str[i+1]=='\0' && str[i]!=' '))
{
w++;
}
}
printf("The number of words = %d", w );
return 0;
}
I know this is an old thread, but perhaps someone needs a simple solution, just checks for blank space in ascii and compares current char to that while also makign sure first char is not a space, cheers!
int count_words(string text){
int counter = 1;
int len = strlen(text);
for(int i = 0; i < len; i++){
if(text[i] == 32 && i != 0) {
counter++;
}
}
return counter;}
Here is another solution:
#include <string.h>
int words(const char *s)
{
const char *sep = " \t\n\r\v\f";
int word = 0;
size_t len;
s += strspn(s, sep);
while ((len = strcspn(s, sep)) > 0) {
++word;
s += len;
s += strspn(s, sep);
}
return word;
}
#include<stdio.h>
int main()
{
char str[50];
int i, count=1;
printf("Enter a string:\n");
gets(str);
for (i=0; str[i]!='\0'; i++)
{
if(str[i]==' ')
{
count++;
}
}
printf("%i\n",count);
}
#include<stdio.h>
#include<string.h>
int getN(char *);
int main(){
char str[999];
printf("Enter Sentence: "); gets(str);
printf("there are %d words", getN(str));
}
int getN(char *str){
int i = 0, len, count= 0;
len = strlen(str);
if(str[i] >= 'A' && str[i] <= 'z')
count ++;
for (i = 1; i<len; i++)
if((str[i]==' ' || str[i]=='\t' || str[i]=='\n')&& str[i+1] >= 'A' && str[i+1] <= 'z')
count++;
return count;
}
#include <stdio.h>
int wordcount (char *string){
int n = 0;
char *p = string ;
int flag = 0 ;
while(isspace(*p)) p++;
while(*p){
if(!isspace(*p)){
if(flag == 0){
flag = 1 ;
n++;
}
}
else flag = 0;
p++;
}
return n ;
}
int main(int argc, char **argv){
printf("%d\n" , wordcount(" hello world\nNo matter how many newline and spaces"));
return 1 ;
}
I found the posted question after finishing my function for a C class I'm taking. I saw some good ideas from code people have posted above. Here's what I had come up with for an answer. It certainly is not as concise as other's, but it does work. Maybe this will help someone in the future.
My function receives an array of chars in. I then set a pointer to the array to speed up the function if it was scaled up. Next I found the length of the string to loop over. I then use the length of the string as the max for the 'for' loop.
I then check the pointer which is looking at array[0] to see if it is a valid character or punctuation. If pointer is valid then increment to next array index. The word counter is incremented when the first two tests fail. The function then will increment over any number of spaces until the next valid char is found.
The function ends when null '\0' or a new line '\n' character is found. Function will increment count one last time right before it exit to account for the word preceding null or newline. Function returns count to the calling function.
#include <ctype.h>
char wordCount(char array[]) {
char *pointer; //Declare pointer type char
pointer = &array[0]; //Pointer to array
int count; //Holder for word count
count = 0; //Initialize to 0.
long len; //Holder for length of passed sentence
len = strlen(array); //Set len to length of string
for (int i = 0; i < len; i++){
//Is char punctuation?
if (ispunct(*(pointer)) == 1) {
pointer += 1;
continue;
}
//Is the char a valid character?
if (isalpha(*(pointer)) == 1) {
pointer += 1;
continue;
}
//Not a valid char. Increment counter.
count++;
//Look out for those empty spaces. Don't count previous
//word until hitting the end of the spaces.
if (*(pointer) == ' ') {
do {
pointer += 1;
} while (*(pointer) == ' ');
}
//Important, check for end of the string
//or newline characters.
if (*pointer == '\0' || *pointer == '\n') {
count++;
return(count);
}
}
//Redundent return statement.
count++;
return(count);
}
I had this as an assignment...so i know this works.
The function gives you the number of words, average word length, number of lines and number of characters.
To count words, you have to use isspace() to check for whitespaces. if isspace is 0 you know you're not reading whitespace. wordCounter is a just a way to keep track of consecutive letters. Once you get to a whitespace, you reset that counter and increment wordCount. My code below:
Use isspace(c) to
#include <stdio.h>
#include <ctype.h>
int main() {
int lineCount = 0;
double wordCount = 0;
double avgWordLength = 0;
int numLines = 0;
int wordCounter = 0;
double nonSpaceChars = 0;
int numChars = 0;
printf("Please enter text. Use an empty line to stop.\n");
while (1) {
int ic = getchar();
if (ic < 0) //EOF encountered
break;
char c = (char) ic;
if (isspace(c) == 0 ){
wordCounter++;
nonSpaceChars++;
}
if (isspace(c) && wordCounter > 0){
wordCount++;
wordCounter =0;
}
if (c == '\n' && lineCount == 0) //Empty line
{
break;
}
numChars ++;
if (c == '\n') {
numLines ++;
lineCount = 0;
}
else{
lineCount ++;
}
}
avgWordLength = nonSpaceChars/wordCount;
printf("%f\n", nonSpaceChars);
printf("Your text has %d characters and %d lines.\nYour text has %f words, with an average length of %3.2f ", numChars, numLines, wordCount, avgWordLength);
}
Here is one solution. This one will count words correctly even if there are multiple spaces between words, no spaces around interpuncion symbols, etc. For example: I am,My mother is. Elephants ,fly away.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int countWords(char*);
int main() {
char string[1000];
int wordsNum;
printf("Unesi nisku: ");
gets(string); /*dont use this function lightly*/
wordsNum = countWords(string);
printf("Broj reci: %d\n", wordsNum);
return EXIT_SUCCESS;
}
int countWords(char string[]) {
int inWord = 0,
n,
i,
nOfWords = 0;
n = strlen(string);
for (i = 0; i <= n; i++) {
if (isalnum(string[i]))
inWord = 1;
else
if (inWord) {
inWord = 0;
nOfWords++;
}
}
return nOfWords;
}
this is a simpler function to calculate the number of words
int counter_words(char* a){`
// go through chars in a
// if ' ' new word
int words=1;
int i;
for(i=0;i<strlen(a);++i)
{
if(a[i]==' ' && a[i+1] !=0)
{
++words;
}
}
return words;}

Resources