Selecting lines with length, C filter - c

I am writing a filter that should select all lines having a specified length. I ended up having this code, but I don't know how to specify n. I mean, n (and optionally m) should be replaced by a number of lines in command prompt, but I have no idea how to describe it in the code. I thought of case "%d", but from what I know it's not possible to write it like that. That's the code I have so far:
#include<stdio.h>
#include<string.h>
int main(int argc, char *argv[])
{
int n;
int m;
char line[200];
while(fgets(line,sizeof(line)/sizeof(char), stdin)!=NULL)
{
if(argc>1){
switch(argv[0][0])
{
case 'n':
strlen(line)==n;
break;
case '#n':
strlen(line)<n;
break;
case 'n m':
strlen(line)>=n && strlen(line)<=m;
break;
case 'n#':
strlen(line) > n;
break;
}
printf("%s\n", line);
}}
return 0;
}
Your help would mean a lot to me! I don't really know how to make it work anymore.

I think you should parse the command line outside of your loop. Assuming you are going to require the caller of your program to specify both n and m on the command line, it's a simple matter of grabbing the first two parameters and converting them to integers, and then loop over your stdard input. Something like this:
/* call this minmax.c */
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char* argv[]) {
int n, m, len;
char line[200];
if (argc < 3) {
printf("Must specify min & max line length.");
return -1;
}
n = atoi(argv[1]);
m = atoi(argv[2]);
while(fgets(line, 200, stdin) != NULL) {
len = strlen(line);
if (len >=n && len <= m)
printf(line);
}
return 0;
}
Assuming you are running on *nix:
cc -ominmax minmax.c
Then call it with the min and max line lengths
./minmax 2 5
This will echo back every line you type that is at least 2 characters, but no more then 5.

I hope I understand well the aim of your desired program and here is the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i=1,n,m; // n and m are the variable which holds
// the limited length
if(argc>=3)
{
// you need to execute the program with this form
// program.exe n m <file.txt
n=atoi(argv[1]); // get the value of n
m=atoi(argv[2]); // get the value of m
printf("n=%d m=%d\n",n,m);
}
char line[1000]; // this variable will hold each line of the file
while (fgets(line,sizeof(line),stdin)) // fgets used to read
{ //the lines in file till the newline
int length=strlen(line)-1;
// we decrement the length to get rid of
// the newline character
if (length < n)
{
printf("line %d:%s status: < %d\n",i,line,n);
}
else if (length==n)
{
printf("line %d:%s status: = %d\n",i,line,n);
}
else if (length>n && length <=m)
{
printf("line %d:%s status: %d < <= %d\n",i,line,n,m);
}
else
{
printf("line %d:%s status: > %d\n",i,line,m);
}
i++;
}
return 0;
}
In case the code does not fit to your needs I think it is sufficient and can be taken as a support for your exact program as it encompasses everything you need !! Hope it helps !!

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;
}

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;
}

Removing dots in a string in C

I'm making a little program in C where I would put in a couple of numbers and dots and then delete all the dots (.).
I was thinking about a whileloop but I cannot seem to quite understand what I should do next. So far I got this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
while (s[k]!=0)
{
//?????
}
return 0;
Am I on the right track or should I start differently and not use a while loop at all? I can only find solutions where there is a specific string that is not written by the user, but by the programmer...
Put in an IF to only print characters that aren't a dot. Like the others suggested, you should probably change the gets to fgets as well.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
while (s[k]!=0) {
if ( s[k] != '.' ) {
printf("%c", s[k]);
}
k++;
}
printf("\n");
return 0;
}
With a while loop, I'm also worried that if the user puts in a full 30 characters, you won't reach your exit condition. To avoid this problem, a for loop would be better (since you already know the size of the array). However, if you do it this way, you'll also need to initialize your array "s" to be blank.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
for ( k = 0 ; k < 30 ; k++ ) {
if ( s[k] != '.' && s[k] != 0 ) {
printf("%c", s[k]);
}
k++;
}
printf("\n");
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
char s[30];
int k=0;
printf("Enter your account number including dots. \n");
gets(s);
printf("Account number without dots:");
while (s[k]!=0)
{
if(s[k] == '.')
s[k] = s[k + 1];
k++;
}
s[k] = '\0';
return 0;
#include <stdio.h>
//remove the specified character from str
char *strrmc(char *str, char ch){
char *from, *to;
from = to = str;
while(*from){
if(*from == ch)
++from;
else
*to++ = *from++;
}
*to = '\0';
return str;
}
int main(int argc, char *argv[]){
char s[30] = "192.169.007";
printf("%s\n", strrmc(s, '.'));//192169007
return 0;
}
Here's one way you might go at it - it's different from how you've started, but can easily be modified. It could be improved on as well, but we can quibble about that in further comments. :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
/* Take account number in as argument to executable */
int dotless_length = 30;
char dotless[dotless_length];
int k = 0;
int i = 0;
while (argv[1][k] != '\0' && i < dotless_length) {
if (argv[1][k] >= 48 && argv[1][k] <= 57) { /* ascii decimal codes for 0-9 */
dotless[i] = argv[1][k];
i++;
}
else if (argv[1][k] != '.') {
printf("invalid input: %c\n", argv[1][k]);
return 1;
}
k++;
}
dotless[i] = '\0'; /* null-terminate it! */
printf("Account number without dots: %s\n", dotless);
return 0;
}
Then compile with gcc -Wall -o zdotless filename.c and run with
./zdotless 401.863.3000 as an example.
Notes: This may look more harder since it goes into input sanitation (and cleanliness) a little more than your original - e.g.
not assuming that user input consists solely of numbers and periods,
saving the resulting dotless string (for presumable future manipulations?),
having one place to change the length of dotless (a step towards not hardcoding it), and
not being interactive.
When you call an executable, argv is what you've typed, so argv[0] is the executable name (./zdotless), argv[1] is the next argument (401.863.3000 as a string), and so on if there are more arguments. Since argv[1] is the string representation of your dotty input number, argv[1][0] is the first character of it, etc.
Since we're copying to dotless character-by-character rather than using string manipulation, you've got to tack on a null character manually. (That same null character is what you'd loop until reaching, when initially reading the input string.) Other questions?...

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.

How to verify a password to have at least one uppercase, lowercase and number in C?

What should i do to make it keep looping until it have at least one uppercase, lowercase and number ?
I'm stuck, really stuck...
char password[100][15];
i=1;
printf("Password [3..10]: ");
gets(password[i]);
while (strlen(password[i])>10 || strlen(password[i])<3 || ) {
do{
printf(" Password must contain at least 1 uppercase, 1 lowercase, and 1 number\nPassword [3..10]: ");
gets(password[i]);
} while (strlen(password[i])>10 || strlen(password[i])<3 );
This should work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int is_legal(char *p) {
int number = 0, lower = 0, upper = 0, length = 0;
for( ; *p; p++) {
number += isdigit(*p);
lower += islower(*p);
upper += isupper(*p);
length++;
}
return number > 0 && lower > 0 && upper > 0 && length > 3 && length < 10;
}
char *my_gets(char *buf, int bufsize, FILE *file) {
if(fgets(buf, bufsize, file) == 0) {
return 0;
}
int n = strlen(buf);
if(buf[n-1] == '\n') buf[n-1] = 0;
return buf;
}
int get_password(char *buf, int bufsize, FILE *file) {
printf("Password [3..10]: ");
if(my_gets(buf, bufsize, file) == 0) {
return -1;
}
while(is_legal(buf) == 0) {
printf(" Password must contain at least 1 uppercase, 1 lowercase, and 1 umber\nPassword [3..10]: ");
if(my_gets(buf, bufsize, file) == 0) {
return -1;
}
}
return 0;
}
int main(void) {
char password[100][15];
int i = 0;
if(get_password(password[i], sizeof(password[i]), stdin) != 0) {
fprintf(stderr, "Error getting password\n");
exit(1);
}
return 0;
}
Use this regular expression:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$
It says that you must have at least one lowercase character, one uppercase character and at least one number PLUS it is less typing than the ctype method.
Example:
#include <regex.h>
int main (int argc, char *argv[])
{
regex_t regex;
int regexResult = regcomp(&regex, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", 0);
regexResult = regexec(&regex, passwordVariableHere, 0, NULL, 0);
if (!regex)
{
// Match
}
}
Look at ctype.h header. Examine every character of password until all conditions (upper, lower, digit) are met. If you reach end of password string and any of conditions are unsatisfied, password is wrong.
Maybe it's an easy way to check the characters position in the ASCII table. You can check all characters as numbers between 65 and 90 for uppsercase characters and the same for lowercase.
For a number you could use atoi() function from standard c library.
Or another possibility is using functions from ctype.h: islower(), isupper() or isdigit().
I don't get very well why you are using an array of 15-chars long passwords, but I suppose your criteria refers to just one of those password and not to the others: you want to check that a password has requirements to be considered a "good" password; this is my understanding. Then...
The function gets is rather unsafe. Avoid using it.
The idea is to ask for a password, check it and loop if it does not fit your criteria. There's not a single way to do it of course.
// include files for I/O funcs
#include <stdio.h>
for(;;)
{
printf("insert pwd: ");
gets(buffer); // argh I've said: don't use this
if ( !pass_criteria(buffer) ) {
printf("criteria are ....\n");
} else break;
}
Then pass_criteria could be something like
// include files for strlen and is* funcs
#include <ctype.h>
#include <string.h>
int pass_criteria(const char *buf)
{
int upcount, lowcount, numcount;
if (strlen(buf) < minimum_pass_len ||
strlen(buf) > max_pass_len) return 0; // 0 being false
for (int i = 0; i < strlen(buf); ++i) {
if (isdigit(buf[i]) numcount++;
if (isupper(buf[i]) upcount++;
if (islower(buf[i]) lowcount++;
}
return numcount > 0 && upcount > 0 && lowcount > 0;
}
It's easy to change criteria, e.g. if you want at least 2 number (digit), put numcount > 1 and so on.
Instead of gets
Gets is dangerous for buffer overflow. Try using e.g. fgets like this:
fgets(buffer, buffer_size, stdin);
where buffer_size is the size of your buffer (15 in your case, but avoid using a literal constant; prefer a proper #define or use sizeof, e.g. sizeof (password[0]). Note also that fgets does not discard final newline.

Resources