How To Check For Non-Alphabetical Characters in String in C - c

The below code (which compiles fine) checks for non-alphabetical characters in a command-line input, however I feel like there's got to be a better way to write this. For example, you can see that there is no code that executes in the core if statement that checks each character in the string. Is there a way to check if one of the characters is not an alphabetical character and throw the error, rather than have the error in the else function?
int main(int argc, string argv[]){
// terminate program if more than one key
if(argc != 2){
printf("error");
return 1;
// check to ensure key characters are alphabetical
} else {
for(int h = 0; h < strlen(argv[1]); h++){
if(isalpha(argv[1][h])){
} else {
printf("error");
return 1;
}
}
}
}

Strings are usually short, but calling strlen() ina for loop condition is a bad habit. It's O(N squared) because the entire string is scanned on each iteration.
Write the function like this
int allalpha(const char *str)
{
size_t i;
for(i=0;str[i];i++)
if(!isalpha(str[i]))
return 0;
return 1;
}
Then in main
if(!allalpha(argv[1]))
{
/* non all-alpha error handling code here */
}

Yes, you can invert the if-condition, which is the general solution in these cases.
int main(int argc, string argv[]){
// terminate program if more than one key
if(argc != 2){
printf("error");
return 1;
} else {
// check to ensure key characters are alphabetical
for(int h = 0; h < strlen(argv[1]); h++){
if(!isalpha(argv[1][h])){
printf("error");
return 1;
}
}
}
}

Related

counting words with arguments, fgets(), strncmp()

i would like to write a code that count how often the argument occurs in the input.
those are the requirements:
It may be assumed
that the lines in the input do not exceed 1024 characters. The string #EOF on the beginning of a line indicates the end of the input. It it not necessary to consider word
boundaries, and overlapping words must be counted as well: with an input of baaaab,
the word aa shall be counted three times. Also, the program must be case sensitive.
i already wrote a code, but i seem to have made some mistakes. Does anyone have an idea?
int main(int argc, char *argv[])
{
char buf[1026]="start";
int count=0;
while (strncmp(buf,"#EOF",4)!=0)
{
fgets(buf, 1025, stdin);
if (strncmp(buf, argv[1], strlen(argv[1]))==0)
{
count++;
}
}
if(argc==1)
printf("Please specify a program argument.");
if(argc>=2)
printf("%d", count);
return 0;
}
this is the program input with the argument let:
Let it be, let it be, let it be, let it be.
Whisper words of wisdom, let it be.
#EOF
and there is no output while it should be 4
this is the program input with argument aa:
aa aaaaa aa
aa aaa
#EOF
and the output is 2 while it should be 9
this is the program input with argument EOF:
De volgende EOF behoort ook tot de invoer: EOF
# Net als deze #EOF. Maar hieronder niet meer.
#EOF
and there is no input while it should be 3
thanks in advance
strncmp() tests for exact equality of the first n characters of each string provided. However, what you want is to count each occurrence, not just if the start of the line matches. For example, if you're looking for "let" in "Let it be, let it be, let it be, let it be.", you're only ever testing "Let" against "let". No match, no count. You never test further down the string.
So what you want to do is to loop over the result of fgets(), like so:
fgets(buf, 1025, stdin);
for (char *p = buf; *p; ++p) {
if (strncmp(p, argv[1], strlen(argv[1])) == 0)
{
count++;
}
}
This will test "let" against "Let", then "et ", then "t i", etc. until you've checked the whole line and counted the matches.
If you were to use strstr() instead of strncmp(), the loop would look like this:
for (char *p = buf; (p = strstr(p, argv[1])); ++p)
{
count++;
}
Your code only counts the first occurrence of the word in each line of input. You need to iterate through each input string to find ALL occurrences. Try something like this:
int main(int argc,char *argv[])
{
char buf[1026] = "start";
int len, matches = 0;
if (argc < 2) {
printf("Please specify a program argument.");
exit(1);
}
len = strlen(argv[1]);
while (strncmp(buf,"#EOF",4) != 0) {
fgets(buf,1025,stdin);
int buflen = strlen(buf);
for (int i = 0; i <= buflen - len; ++i) {
if (strncmp(&buf[i],argv[1],len) == 0)
++matches;
}
}
printf("'%s' found %d times\n",argv[1],matches);
return 0;
}
This is a functional and correct code written based on the answer given by Fred Larson
Big thanks to him.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
char buf[1026]="start";
int N;
int count=0;
char *p;
if(argc==1)
{
printf("Please specify a program argument.\n");
return(1);
}
N=strlen(argv[1]);
while (strncmp(buf,"#EOF",4)!=0)
{
fgets(buf, 1025, stdin);
for (p = buf;*p;p++)
{
if (strncmp(p, argv[1], N)==0)
{
if (strncmp(buf,"#EOF",4)!=0)
count++;
}
}
}
if(argc>=2)
printf("%d\n", count);
return 0;
}

Vigenere cs50 doesn't complain when lacks second arg

I don't understand why it isn't working. It complains when there are 3 or more args but not when there is only the one Vigenere arg. I have looked at other people who had same problem and they said this worked to resolve.....not sure what I am missing here. When I run ./vigenere, I get a segmentation fault. It works normally with 2 arg like ./vigenere bard and complains when extra arguments are given like ./vigenere bard dfads.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc,string argv[])
{
string sKeyWord = argv[1];
int iKeyLength = strlen(sKeyWord);
int iKey[iKeyLength];
string sPlainText = "";
int counter = 0;
int iAccept = 0;
do
{
if(argc != 2) // <-----this should work whats wrong?
{
printf("Invalid argument! Please enter program name and keyword.\n");
return 1;
}
else if(argv[1])
{
for(int i = 0; i < iKeyLength; i++)
{
if (!isalpha(argv[1][i]))
{
printf("Invalid entry, please use letters only.\n");
return 1;
}
else
{
iAccept = 1;
}
}
}
}while(iAccept == 0);
for(int i = 0; i < iKeyLength; i++)
{
iKey[i] = toupper(sKeyWord[i]) - 65;
}
sPlainText = GetString();
int iPlainText = strlen(sPlainText);
for(int j = 0; j < iPlainText; j++)
{
if(!isalpha(sPlainText[j]))
{
printf("%c",sPlainText[j]);
counter++;
}
if(islower(sPlainText[j]))
{
printf("%c",((((sPlainText[j] - 97) + iKey[(j - counter)%iKeyLength])%26)+ 97));
}
if(isupper(sPlainText[j]))
{
printf("%c",((((sPlainText[j] - 65) + iKey[(j - counter)%iKeyLength])%26)+ 65));
}
}
printf("\n");
return 0;
}
I'd rewrite the top, argument handling section of your program like this.
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s key\n", argv[0]);
return 1;
}
char *sKeyWord = argv[1];
int iKeyLength = strlen(sKeyWord);
int iKey[iKeyLength];
for (int i = 0; i < iKeyLength; i++)
{
if (!isalpha(sKeyword[i]))
{
fprintf(stderr, "%s: Invalid character '%c' in key; please use letters only.\n",
argv[0], sKeyword[i]);
return 1;
}
iKey[i] = toupper(sKeyWord[i]) - 'A';
}
…your code to read the text to be enciphered and encipher it, etc…
The key point is to check that there is an argv[1] before trying to do anything with it. I eliminated a do { … } while (…); loop because the argument isn't going to change on a second iteration. That allows the iAccept variable to be eliminated. Note that errors are reported on standard error, not standard output. Also notice that the messages are preceded by the program name (argv[0]). A 'Usage' message is often the best way to report a problem; it's a simple reminder to those who run the program what's required. Note too that the error message for the alphabetic check reports the erroneous character; that helps people see what the program thinks is wrong.
This is more or less what the comments were suggesting should be done.
I've not reviewed the enciphering code; there could be undiagnosed problems in that too. There are many related questions on SO that would provide you with answers to any such problems, though.

Get text while not EOF

Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define N 256
int main(int argc, const char * argv[]) {
char testo[N];
int i;
printf("PER TERMINARE L'INSERIMENTO PREMERE CTRL+Z oppure CTRL+D \n");
for(i=0;i<N;i++)
{
scanf("%c",&testo[i]);
/* if(testo[i]=='h' && testo[i-1]=='c')
{
i--;
testo[i]='k';
}
if(testo[i]==testo[i-1])
{
i--;
} */
if(testo[i]==EOF)
{
break;
}
}
puts(testo);
return 0;
}
When the code in /* ... */ is compiled, I can't stop the insert of text with EOF, but when the code is built and run as shown here, the EOF works.
Does anyone have any idea what the problem is?
You're testing for EOF incorrectly. With scanf(), you need to look at the return value. In fact, with almost all input functions, you need to test, if not capture and test, the return value.
Superficially, you need:
for (i = 0; i < N; i++)
{
if (scanf("%c", &testo[i]) == EOF)
break;
…
}
However, in general, you should check that scanf() made as many successful conversions as you requested, so it is better to write:
for (i = 0; i < N; i++)
{
if (scanf("%c", &testo[i]) != 1)
break;
…
}
In this example, it really won't matter. If you were reading numeric data, though, it would matter. The user might type Z instead of a number, and scanf() would return 0, not EOF.
To detect EOF, check the result of scanf()
if scanf("%c",&testo[i]) == EOF) break;
Note: testo[] may not be null character terminated. To print as a string, insure it is.
char testo[N];
int i;
// for(i=0;i<N;i++) {
for(i=0;i<(N-1);i++) {
if (scanf("%c",&testo[i]) == EOF) break;
}
testo[i] = '\0'; // add
puts(testo);
To stop at end of file, check the return value from scanf:
scanf returns the number of inputs correctly parsed. In your case, %c reads a byte from the stream correctly as long as end of file has not been reached. if (scanf("%c",&testo[i]) != 1) break; will do.
Yet using scanf to read one byte at a time from the input stream is overkill. The idiomatic way to do this in C is using the getchar() or the getc() function. The return value must be stored in an int variable and has special value EOF upon end of file.
You should also make the array 1 byte longer and store a null byte at the end to make it a C string, as expected by puts.
Here is a modified version of your program:
int main(int argc, const char *argv[]) {
char testo[N+1];
int i;
printf("PER TERMINARE L'INSERIMENTO PREMERE CTRL+Z oppure CTRL+D\n");
for (i = 0; i < N; i++) {
int c = getchar();
if (c == EOF)
break;
testo[i] = c;
/* ... further processing ... */
}
testo[i] = '\0';
puts(testo);
return 0;
}

Processing outputs of multiple inputs in C

It's not something trivial but I would like to know the best way to process multiple outputs, for example:
Input
First line of input will contain a number T = number of test cases. Following lines will contain a string each.
Output
For each string, print on a single line, "UNIQUE" - if the characters are all unique, else print "NOT UNIQUE"
Sample Input
3
DELHI
london
#include<iostream>
Sample Output
UNIQUE
NOT UNIQUE
NOT UNIQUE
So how can I accomplish outputs like that? My code so far is:
int main(int argc, char *argv[])
{
int inputs, count=0;
char str[100];
char *ptr;
scanf("%d",&inputs);
while(inputs-- >0)
{
scanf("%s",str);
for(ptr=str; *ptr!='\0';ptr++)
{
if( *ptr== *(ptr+1))
{
count++;
}
}
if(count>0)
{
printf("NOT UNIQUE");
}
else
{
printf("UNIQUE");
}
}
}
But the above will obviously print the output after each input, but I want the output only after entering all the inputs, if the user enters 3, then the user have to give 3 strings and after the output will be given whether the given strings are unique or not. So I want to know how can I achieve the result given in the problem. Also another thing I want to know is, I am using an array of 100 char, which it can hold a string up to 100 characters, but what do I have to do if I want to handle string with no limit? Just declaring char *str is no good, so what to do?
Hope this helps:
#include <stdio.h>
int main(int argc, char *argv[])
{
int inputs,count=0;
char str[20];
scanf("%d",&inputs);
char *ptr;
char *dummy;
while(inputs-- >0)
{
scanf("%s",str);
for(ptr=str; *ptr!='\0';ptr++)
{
for(dummy=ptr+1; *dummy != '\0';dummy++)
{
if( *ptr== *dummy)
{
count=1;
}
}
if(count == 1)
break;
}
if(count>0)
{
printf("NOT UNIQUE");
}
else
{
printf("UNIQUE");
}
}
}
If you want to save stuff for later use, you must store it somewhere. The example below stores up to 10 lines in buf and then points str to the current line:
#include <stdlib.h>
#include <stdio.h>
#include <string.h> /* for strlen */
#include <ctype.h> /* for isspace */
int main(int argc, char *argv[])
{
int ninput = 0;
char buf[10][100]; /* storage for 10 strings */
char *str; /* pointer to current string */
int i;
printf("Enter up to 10 strings, blank to and input:\n");
for (i = 0; i < 10; i++) {
int l;
str = buf[i];
/* read line and break on end-of-file (^D) */
if (fgets(str, 100, stdin) == NULL) break;
/* delete trailing newline & spaces */
l = strlen(str);
while (l > 0 && isspace(str[l - 1])) l--;
str[l] = '\0';
/* break loop on empty input */
if (l == 0) break;
ninput++;
}
printf("Your input:\n");
for (i = 0; i < ninput; i++) {
str = buf[i];
printf("[%d] '%s'\n", i + 1, str);
}
return 0;
}
Note the two separate loops for input and output.
I've also rejiggled your input. I'm not very fond of fscanf; I prefer to read input line-wise with fgets and then analyse the line with strtok or sscanf. The advantage over fscanf is that yout strings may contain white-space. The drawback is that you have a newline at the end which you usually don't want and have to "chomp".
If you want to allow for longer strings, you should use dynamic allocation with malloc, although I'm not sure if it is useful when reading user input from the console. Tackle that when you have understood the basics of fixed-size allocation on the stack.
Other people have already pointed you to the error in your check for uniqueness.

strlen inconsistent with zero length string

I'm creating a DataStage parallel routine, which is a C or C++ function that is called from within IBM (formerly Ascential) DataStage. It is failing if one of the strings passed in is zero length. If I put this at the very first line of the function:
return strlen(str);
then it returns 0 for the calls that pass in empty values into str. If I put this at the first line, however...
if (strlen(str)==0) {return 0;}
then it does not return and goes into an infinite loop
I'm baffled - it works fine in a test harness, but not in DataStage.
Maybe there is something odd about the way DataStage passes empty strings to C routines?
int pxStrFirstCharList(char *str, char *chars )
{
if (strlen(str)==0) {return 0;}
if (strlen(chars)==0) {return 0;}
int i = 0;
//Start search
while (str[i]) //for the complete input string
{
if (strchr(chars, str[i]))
{
return i+1;
}
++i;
}
return 0;
}
There is a builtin function for what you are doing, it's called strcspn. This function takes two strings, and searches the first one for the first occurance of any of the characters of the second string.
I suggest using that than RYO...
http://www.cplusplus.com/reference/clibrary/cstring/strcspn/
How about this?
int pxStrFirstCharList(char *str, char *chars )
{
if (str && chars && (0 != strlen(str)) && (0 != strlen(chars)))
{
int i = 0;
//Start search
while (str[i]) //for the complete input string
{
if (strchr(chars, str[i]))
{
return i+1;
}
++i;
}
}
return 0;
}
Also, I don't quite get the point of the while loop ... (and no, I don't mean that this could be written as for). What I mean is that on one hand you are doing a search (strstr) that itself will be implemented as a loop and still you have some outer loop. Could it be that you actually wanted to have chars in its place, i.e.:
int pxStrFirstCharList(char *str, char *chars )
{
if (str && chars && (0 != strlen(str)) && (0 != strlen(chars)))
{
int i = 0;
//Start search
while (chars[i]) //for the complete input string
{
if (strchr(str, chars[i]))
{
return i+1;
}
++i;
}
}
return 0;
}
...? That is, look for each of the characters within chars inside the string denoted by str ...
If NULL is not explicitly part of the game, at least during development phase, it's always a good idea to add a precondition check on pointers received by a function:
int pxStrFirstCharList(char *str, char *chars )
{
if (!str)
return -1;
if (!chars)
return -2;
....
(The negative values -1 and -2 than tell the caller that something went wrong)
Or doing it in a more relaxed way, silently accepting NULL pointer strings as ""-string:
int pxStrFirstCharList(char *str, char *chars )
{
if (!str)
return 0;
if (!chars)
return 0;
...
If you are the only one using this API you could #ifndef BUILD_RELEASE these checks away for a release build if anything is tested stable.
I guess it is the strlen's issue when the length of the string is 0. For example,
char s1[0];
char *s2="a";
printf("%d %s\n", sizeof(s1), s1);//0 #
printf("%d %s\n", strlen(s1), s1);//3 #
printf("%d %s\n", sizeof(s2), s2);//8 a
printf("%d %s\n", strlen(s2), s2);// 1 a
You will get a weird answer for using strlen and you can check its source code in detail(https://code.woboq.org/userspace/glibc/string/strlen.c.html). In nutshell, you can use sizeof instead of strlen for char string or avoid 0 length case by using strlen.

Resources