Setting number of looping - c

I have problem. I need functions in tool.c file to loop only number of times that are required. Like it stops after looping thru whole input. My teacher said I should pass second argument, but class finished and I don't know how it should look.
main.c
#include <stdio.h>
#include <stdlib.h>
#include "tools.h"
int main(int argc, char *argv[]) {
int count[256] = { 0 };
int c;
while ( (c=getchar())!=EOF ){
count[c]++;
}
switch (argc > 1 && argv[1][1]) {
case 'm': case 'M':
mostOften(count);
break;
case 'l': case 'L':
leastOften(count);
break;
default:
mostOften(count);
break;
}
return 0;
}
tools.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include "tools.h"
void mostOften(int *s) {
int j, a = 0;
int max=0, cha;
for(j=32; j<126; j++){
if(s[j]>max) {
max=s[j];
cha=j;
}
a++;
}
printf("char %c: %d times\n", cha, max);
}
void leastOften(int *s) {
int j, a = 0;
int min=INT_MAX, cha;
for(j=32; j<126; j++){
if(s[j] && s[j]<=min) {
min=s[j];
cha=j;
}
a++;
}
printf("char %c: %d times\n", cha, min);
}
For example if I input
paragraph
I want it to loop only 9 times, basically I need to set some if statment to stop looping

From looking at how you have the problem setup, it looks like you are confusing iterating over the character that are part of the input, and the array that holds the frequency of the characters read.
For starters, to make your code readable, don't use magic numbers in your code, e.g. 32 and 126. Instead use the characters you are attempting to represent, e.g. (space) and ~ (tilde). For example, instead of using:
for(j=32; j<126; j++){
you could use:
for(j = ' '; j < '~'; j++){
That too has it's pitfalls. Why? You don't want to loop over characters, you actually want to loop over the elements in your count array that hold the frequency each character occurs in input. In other words, you need an array holding at minimum 95 integers which will hold the frequency each character occurs in your input. Since you know how may characters that will be, don't obscure it behind 32 to 126, just declare a constant for your array size (maybe called ARSZ) in tools.h, e.g.
#define ARSZ 95
Then after reading your input and filling the count array, it is just a matter of iterating over the count array once to get either the mostoften or leastoften number. Further, since you have a constant for the number of elements in count you do NOT need to pass the size of count to mostoften and leastoften -- you already know how many elements are present, 95. (see below for notes on iterating only over the characters present in input)
(if the array size is Not constant (and you are not passing an array with a sentinel like a nul-terminated string) or the number of elements you need to iterate over is not known at compile time, then you DO need to pass the size of the array to the functions.
(and another quick aside, C generally uses all lower-case for variable names, reserving all upper-case for constants and macros. You will not ordinarily see MixedCase or camelCase variable names in C, leave that for C++)
Next, while you should use getopt for processing command line arguments, you can use a quick hack of checking the second character of the arguments at issue, but you need to validate you have at least one argument to check and that the argument isn't an empty-string. Basically, you want to check:
if (argc > 1 && *argv[1]) /* check argc & not empty-string */
switch (argv[1][1]) {
case 'm':
mostoften (count);
break;
case 'M':
mostoften (count);
break;
case 'l':
leastoften (count);
break;
case 'L':
leastoften (count);
break;
default:
fprintf (stderr, "warning: unrecognized option, using 'mostoften'.\n");
mostoften (count);
}
else {
fprintf (stderr, "warning: no option given using 'mostoften'.\n");
mostoften (count);
}
note: you can't put two constant conditions together for any single case of your switch (some compilers provide non-standard extensions). Also note, you do not need a break in the default case, there is no fall-through possible.
Putting it altogether, you could write your tools.h similar to:
#include <stdio.h>
#include <limits.h>
#define ARSZ 95
int mostoften (int *a);
int leastoften (int *a);
Your tools.c as:
#include "tools.h"
int mostoften (int *a) {
int i, max = INT_MIN, cha = '0';
for (i = 0; i < ARSZ; i++)
if (a[i] > max) {
max = a[i];
cha = i + ' ';
}
printf ("char '%c' : %d times\n", cha, max);
return max;
}
int leastoften (int *a) {
int i, min = INT_MAX, cha = '0';
for (i = 0; i < ARSZ; i++)
if (a[i] < min) {
min = a[i];
cha = i + ' ';
}
printf ("char '%c' : %d times\n", cha, min);
return min;
}
You do know that if the max or min is the same for 2 different characters, you will select the first, and in the case of leastoften you will always select the first character with 0 frequency. To correct this problem, you will need to keep a second array (or 2D array, or struct) that tracks which characters were present in the input and only consider the frequency for those characters.
Finally, your main.c could be written something like:
#include "tools.h"
int main (int argc, char **argv) {
int c = 0, count[ARSZ] = {0};
while ((c = getchar ()) != EOF)
if (' ' <= c && c <= '~')
count[c - ' ']++;
if (argc > 1 && *argv[1]) /* check argc & not empty-string */
switch (argv[1][1]) {
case 'm':
mostoften (count);
break;
case 'M':
mostoften (count);
break;
case 'l':
leastoften (count);
break;
case 'L':
leastoften (count);
break;
default:
fprintf (stderr, "warning: unrecognized option, using "
"'mostoften'.\n");
mostoften (count);
}
else {
fprintf (stderr, "warning: no option given using 'mostoften'.\n");
mostoften (count);
}
return 0;
}
There are many different ways to accomplish this task, but given your initial code, this keeps with what appeared to be your intent. Look it over and let me know if you have any questions. If you want the easiest way to track the characters present in your input without using a struct, then simply declaring count as count[ARSZ][2] and using the additional element to indicate which characters were present would do. (you can pass the array to your functions as int a[][2] or int (*a)[2]) Good luck.

Related

Peculiar memory/printing issue C

#include<stdio.h>
#include<stdlib.h>
#include <string.h>
int main(void){
char dnachar [10]
int cytosine; //first int
int thymine; //second int
int guanine;
int adenine;
printf("Enter DNA Sequence ");
scanf("%10s",dnachar);
printf("dna:%s\n", dnachar);
for (int i = 0; i < 10; i++){
char x = dnachar[i];
if(x == 'c')
cytosine++;
if(x == 't')
thymine++;
if(dnachar[i] == 'g')
guanine++;
if(dnachar[i] == 'a')
adenine++;
}
printf("%d,%d,%d,%d",thymine, guanine, cytosine, adenine);
return 0;
}
Hi, I am new to C and I noticed that the program only prints the first two ints accurately - cytosine and thymine. The others show a random string of incoherent numbers. Why is that and how can I fix it?
edit: I changed i<20 to i<10, I don't know how I made that mistake.
Among the multitude of things wrong in this code
Wrong format limiter
Given:
char dnachar[10];
The code:
scanf("%10s",dnachar);
will read a string up to 10 characters long, not including the terminating null, which it will always place. Therefore, that scanf can write as many as eleven (11) chars in a space only declared to hold ten (10). The result of a ten character string read (or longer) will be undefined behavior.
Solution:
if (scanf("%9s", dnachar) != 1)
return EXIT_FAILURE;
Note: if your sequences are really ten characters each, then dnachar should be declared as:
char dnachar[11]; // account for 10-chars + terminator
And the format string for scanf should be %10s accordingly.
Indeterminate Counters
All four of your counters are indeterminate. They have no specified initial value as automatic variables, and therefore operations expecting predictable results are unfounded. If they had static linkage (either globals or declared static) they would have default values of 0, but that isn't what your code does.
Solution:
int cytosine = 0;
int thymine = 0;
int guanine = 0;
int adenine = 0;
Incorrect Loop Limit
Given:
for (int i = 0; i < 20; i++){
char x = dnachar[i];
This assumes there are twenty characters in dnachar (which is impossible unless you've invoked undefined behavior from the item above). One you access dnachar[10] and beyond, more undefined behavior. Ideally you stop processing chars when there are no more, which is much easier with a pointer than an index.
Solution:
for (char *p = dnachar; *p; ++p)
{
switch(*p)
{
case 'c':
++cytosine;
break;
case 't':
++thymine;
break;
case 'g':
++guanine;
break;
case 'a':
++adenine;
break;
default:
break;
}
}

My program doesn't manipulate a string's values correctly

I need to code a program that gets input values for a string, then it ignores the characters that are not digits and it uses the digits from the string to create an integer and display it. here are some strings turned into integers as stated in the exercise.
I wanted to go through the string as through a vector, then test if the each position is a digit using isdigit(s[i]), then put these values in another vector which creates a number using the digits. At the end it's supposed to output the number. I can't for the life of it figure what's wrong, please help.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main()
{
char *s;
scanf("%s", s);
printf("%s\n", s);
int i, n=0, v[100], nr=0;
for(i=0; i<strlen(s); i++)
{
if (isdigit(s[i]) == 1)
{
v[i] = s[i];
n++;
}
}
for(i=0;i<n;i++)
{
printf("%c\n", v[i]);
}
for(i=0; i<n; i++)
{
nr = nr * 10;
nr = nr + v[i];
}
printf("%d", nr);
return 0;
}
The pointer s is unintialized which is your major problem. But there are other problems too.
isdigit() is documented to return a non-zero return code which is not necessarily 1.
The argument to isdigit() needs to be cast to unsigned char to avoid potential undefined behaviour.
Your array v is also using the same index variable i - which is not right. Use a different variable to index v when you store the digits.
You need to subtract '0' to get the each digits integer equivalent.
scanf()'s format %s can't handle inputs with space (among other problems). So, use fgets().
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char s[256];
fgets(s, sizeof s, stdin);
s[strcspn(s, "\n")] = 0; /* remove trailing newline if present */
printf("%s\n", s);
int i, n = 0, v[100], nr = 0;
size_t j = 0;
for(i = 0; i < s[i]; i++)
{
if (isdigit((unsigned char)s[i]))
{
v[j++] = s[i];
n++;
}
}
for(i = 0;i < j; i++)
{
printf("%c\n", v[i]);
}
if (j) { /* No digit was seen */
int multiply = 1;
for(i= j-1 ; i >= 0; i--) {
nr = nr + (v[i] - '0') * multiply;
multiply *= 10;
}
}
printf("%d", nr);
return 0;
}
In addition be aware of integer overflow of nr (and/or multiply) can't hold if your input contains too many digits.
Another potential source of issue is that if you input over 100 digits then it'll overflow the array v, leading to undefined behaviour.
Thanks a lot for your help, i followed someone's advice and replaced
v[i] = s[i] -> v[n] = s[i] and changed char *s with char s[100]
now it works perfectly, i got rid of the variable nr and just output the numbers without separating them through \n . Thanks for the debugger comment too, I didn't know I can use that effectively.
Firstly, you did not allocate any memory, I changed that to a fixed array.
Your use of scanf will stop at the first space (as in the first example input).
Next, you don't use the right array index when writing digits int v[]. However I have removed all that and simply used any digit that occurs.
You did not read the man page for isdigit. It does not return 1 for a digit. It returns a nonzero value so I removed the explicit test and left it as implicit for non-0 result.
I changed the string length and loop types to size_t, moving the multiple strlen calls ouside of the loop.
You have also not seen that digits' character values are not integer values, so I have subtracted '0' to make them so.
Lastly I changed the target type to unsigned since you will ignore any minus sign.
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(void)
{
char s[100]; // allocate memory
unsigned nr = 0; // you never check a `-` sign
size_t i, len; // correct types
if(fgets(s, sizeof s, stdin) != NULL) { // scanf stops at `space` in you example
len = strlen(s); // outside of the loop
for(i=0; i<len; i++) {
if(isdigit(s[i])) { // do not test specifically == 1
nr = nr * 10;
nr = nr + s[i] - '0'; // character adjustment
}
}
printf("%u\n", nr); // unsigned
}
return 0;
}
Program session:
a2c3 8*5+=
2385
Just use this
#include <stdio.h>
#include <ctype.h>
int main()
{
int c;
while ((c = getchar()) != EOF) {
switch (c) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '\n':
putchar(c); break;
}
}
return 0;
} /* main */
This is a sample execution:
$ pru_$$
aspj pjsd psajf pasdjfpaojfdapsjd 2 4 1
241
1089u 0u 309u1309u98u 093u82 40981u2 982u4 09832u4901u 409u 019u019u 0u3 0ue
10890309130998093824098129824098324901409019019030
Very elegant! :)

Unable to read all characters(using getchar) inside for loop

Code:
//Program to find no of vowels
#include<stdio.h>
int main()
{
int count;char letter;int vowel=0;
for(count=0;count<10;count++)
{
letter=getchar();
switch(letter)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':vowel++;
}printf("Count:%d",count);
}
printf("NO of vowels is %d\n",vowel);
return 0;
}
Output:
a
a
s
d
f
NO of vowels is 2
The program reads only 5 characters and then displays the expected output. I tried printing the value of 'count' and by the end of loop, it incremented to 10. But,I am not able to read the number of characters(10) equivalent to my for loop condition. Please help.
I'm surprised you didn't notice from the printf("Count: %d\n"); line that the count increments by two for each letter of input. The getChar function gets all of the characters from the input text, including spaces and newlines. The simplest way to make your program behave as you expect is to increase the maximum count to 20:
for(count = 0; count < 20; count++)
{
letter = getchar();
// ...
Alternatives include using scanf and checking for reaching the end of text input, but your implementation is much safer.
Space ' ' is also a character. getchar reads a character at a time and hence reads ' ' too. Remove spaces from the input.
#include <stdio.h>
#include <ctype.h>
int main(){
int count=0, vowel=0;
char letter;
while(count < 10){
letter=getchar();
if(isgraph(letter)){
switch(tolower(letter)) {
case 'a':
case 'e':
case 'i':
case 'o':
case 'u':vowel++;
}
++count;//Counting only the case of the display characters that are not blank
}
}
printf("NO of vowels is %d\n",vowel);
return 0;
}

Function that counts chars in a string in C

I am new a C. I would like to get help to finish my function.
The mission is:
Write a function that accepts a string maximum length of 256 characters containing characters from 'a' to 'z'.
The function to print the number of occurrences of each character.
For example: input abba output will be:
a = 2 b = 2 c = 0 d = 0 .... z = 0
Do not use if during any function.
I would like to get your help to finish this program please.
This is my code
#include "stdlib.h"
#include "conio.h"
#include "stdio.h"
#include "string.h"
#define size 256
void repeat(char *str);
void main()
{
char str[size];
printf("Please enter a string:\n");
flushall;
gets(str);
repeat(str);
system("pause");
return ;
}
void repeat(char *str)
{
char temp=strlen(str);
int i, count=0;
do
{
for (i=0; i<temp ; i++)
{
count += (*str == str[temp-i]);
}
printf("Char %c appears %d times\n ",*str,count);
count=0;
}
while(*(str++));
}
Please enter a string:
abbba
Char a appears 1 times
Char b appears 2 times
Char b appears 1 times
Char b appears 0 times
Char a appears 0 times
Char appears 0 times
Press any key to continue . . .
this is the output!
I would like to do it in the same building i did.
and should be like
Char a appears 2 times
Chars b appears 3 times
You make a stipulation about not using if. This satisfies that restriction.
#include <stdio.h>
int main(void) {
int i, c;
int counts[256] = { 0 };
const char lower[] = "abcdefghijklmnopqrstuvwxyz";
while ((c = getchar()) != EOF) {
counts[c] += 1;
}
for (i = 0; lower[i]; ++i) {
c = lower[i];
printf("Char %c appears %d times.\n", c, counts[c]);
}
return 0;
}
The problem with your attempt is that you do not track any state to remember which characters you have already printed information about. It also fails to include the character under consideration as part of the count. It also makes multiple passes over the string to collect count information about each character, but that doesn't affect correctness, just performance. If you can somehow remember which character you have already printed out information for, so that you don't do it again when the same character appears later in the string, your method should print out the counts for the characters that appear. Afterwards, you would need to print out zero counts for the characters that did not appear at all. If the outputs need to be in alphabetical order, then you need to make sure you take care of that as well.
One way to track the information properly and to allow your output to be printed in alphabetical order is to maintain counts for each character in an array. After making a pass over the string and incrementing the count associated with each found character, you can iterate over the count array, and print out the counts.
The following program is for zubergu:
#include <stdio.h>
#include <string.h>
int main (void) {
int i, c;
int counts[26] = { 0 };
const char lower[] = "abcdefghijklmnopqrstuvwxyz";
while ((c = getchar()) != EOF) {
switch (c) {
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
case 'v': case 'w': case 'x': case 'y': case 'z':
counts[strchr(lower, c) - lower] += 1;
break;
default:
break;
}
}
for (i = 0; lower[i]; ++i) {
printf("Char %c appears %d times.\n", lower[i], counts[i]);
}
return 0;
}
It might be one of the ugliest solutions, but also the simplest:
while(*str!='\0')
{
switch(tolower(*str))
{
case 'a': a_count++;break;
case 'b': b_count++;break;
.
.
.
}
str++;
}
It checks if str points to valid letter, then turns it to lower, so it's not case sensitive('A' will be same as 'a' character). No 'if' used and will work with every length char array terminated with '\0' char.
EDIT I have edited the program to follow the requirements of #SagiBinder.
(In my old version, I used an if sentence that checked if the character is in the set 'a'...'z').
The type of temp must be "bigger", that is, something different to char.
Try int, instead.
The algorithm would be this (some details of your program are not repeated here):
int temp = strlen(str);
int i, j;
unsigned char c;
int ch[UCHAR_MAX]; // The macro CHAR_MAX needs the header <limits.h>
for (i = 1; i <= UCHAR_MAX; i++)
ch[i] = 0;
for (j=0; j<temp ; j++) {
c = (unsigned char)(str[j]);
ch[c]++;
}
for (c = 'a'; c <= 'z'; c++)
printf("%c == %d\n", c, ch[c]);
The variable temp holds the length of the string str.
The macro UCHAR_MAX (existing in the header <limits.h>, that you have to #include at the beginning of the program). It is the max. value that holds in a unsigned char.
The array ch[] contains a component for each possible value in the range of the type unsigned char. The intent is that, for some character c, the element ch[c] is the amount of times that c is in str.
I have used unsigned char in order to ensures that the index c of the array ch[] when writting ch[c] is a non-negative integer value, because an array cannot have negative indexes.
The 2nd for goes through the string str. In the step number j, the j-th character of the string str is taken.
This character is a value of type char.
Since one cannot be sure that char have not negative values, I have converted it to (unsigned char) with an explicit cast.
This value is held in the variable c.
The value of c has the (unsigned char version of the) j-th character in str,
so we are going to count it.
How?
Well, we access the array of counters: ch[] with index c, and increment its value in 1:
ch[c]++;
After the for is finished, we have in the array ch[] the information we want.
Finally, we check for the characters from 'a' to 'z'.
(For this, we have supposed that the character encodings in our system follow the convention that the letters have contiguous values).
The 3rd for goes from 'a' to 'z', and the values of the letter (the variable c that controls the for) and the counting of this letter, that is, ch[c].
Moreover: to show the count of any character, you need a re-cast to char, in this way:
printf("%c: %d\n", (char)c, ch[c]);
But this is not necessary with the letters 'a' to 'z', because they belong to the basic execution character set which means that their values are non-negative and equal to their unsigned char counterparts. So, in this case, it is enough to write:
printf("%c: %d\n", c, ch[c]);
EDIT 2: I will use the idea in the answer of #jxh to improve my code.
Since it cannot be guaranted that the encodings of letters 'a' to 'z' are in contiguous order, we can use a string holding the letters:
char letters[] = "abcdefghijklmnopqrstuvwxyz";
The "last" element is, by C convention, a \0 character held after the element 'z'.
Now, we can show the letter counting by changing the 3rd `for` in this way:
for (i = 0; letter[i] != '\0'; i++)
printf("%c == %d\n", letter[i], ch[letter[i]]);
This is equivalent to write:
for (i = 0; letter[i] != '\0'; i++) {
c = letter[i];
printf("%c == %d\n", c, ch[c]);
}
Optimized solution. complexity O(N), N - Input String length.
your void repeat function will be like this,
void repeat(char *str)
{
int temp=strlen(str);// use int here
int i, count=0;
int charCount[26] = {0};
#if 0
//your logic, traverses the string (n*n) time, n - input string length.
do
{
for (i=0; i<temp ; i++)
{
count += (*str == str[temp-i]);
}
printf("Char %c appears %d times\n ",*str,count);
count=0;
}
while(*(str++));
#endif
#if 1
// This logic traverses string once only. n time, n - input string length.
for (i=0; i<temp ; i++)
{
charCount[str[i]%'a']++;
}
for (i=0; i<26 ; i++)
{
printf("%c appears : %d times \n", 'a'+i, charCount[i]);
}
#endif
}
[EDIT]
Here
charCount[str[i]%'a']++; // 'a' is used a its ASCII Value.
You can use it as
charCount[str[i]%97]++;
If you wan to count lower case letter and upper case letter both.
use it like this
if(str[i] >= 'a' && str[i] <= 'z'){
iMap = str[i]%97; // 97 is ASCII Value of 'a'
charCount[iMap]++;
}else if(str[i] >= 'A' && str[i] <= 'Z'){
iMap = str[i]%65; // 65 is ASCII Value of 'A'
charCount[iMap]++;
}
//iMpa is a integer (int iMap;), used for better undersanding.
i = 0;
while (s[i] !=0)
if (( s[i] >= 'a' && s[i] <= 'z') || (s[i] <= 'A' && s[i] >= 'Z'))
{
letters++;
i++;
}
else
if (( s[i] >= '!' && s[i] <= ')'))
{
other++;
}
else
if (( s[i] >= '0' && s[i] <= '9'))
{
numbers++;
}
total = letters + numbers + other;

How to count the number of different type of characters in file using C.

The characters may contain any numeric, alphabets, symbols such as :;# etc.
one method is to use a switch case statement as show below. but thats going to be simple and long process. Is there any other method short method possible?
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int main(void) {
FILE *fp;
fp = fopen("input.txt","r");
int ch,count[36]= {0};
if (fp == NULL)
{
fprintf(stderr,
"Failed to open input.txt: %s\n",
strerror(errno));
}
else
{
while ((ch = fgetc(fp)) != EOF)
{
switch (ch)
{
case 'a':
count[0]++;
break;
case 'b':
count[1]++;
break;
default:
count[2]++;
}
}
fclose(fp);
}
printf("count a is %d", count[0]);
printf("count b is %d", count[1]);
printf("count c is %d", count[2]);
return 0;
}
In ASCII, printable characters have codes from 0x20 to 0x7E, so less than 128 characters. So for ASCII just use an array of 128 characters:
int count[128] = {0};
Update your count with:
count[ch]++;
and print printable characters with something like this:
for (i = 0x20; i <= 0x7E; i++)
{
printf("count %c is %d", i, count[i]);
}
Use an array of size 2^8 and increase the corresponding member.
while ((ch = fgetc(fp)) != EOF)
{
characters[ ch ] += 1 ;
....
The index of the array characters fits the asci table.
if you are reading ASCII characters:
frequency[ch]++;
where frequency is integer array of size 128
If you use the functions from <ctype.h> (isalpha, isdigit, ispunct, etc) in a series of if statements inside your while loop, you could categorize them fairly easily.
PS: for a list of these functions, see:
http://www.cplusplus.com/reference/cctype/

Resources