Only using getchar() and putchar(). For example having entered "asf****f*d" you get "asf++f*d". The signal of the input's end is the symbol '.'. My best attempt is:
char c = 0, flag = 0; int k = 0;
while ((c = getchar()) !='.')
{
if (c == '*') { k++; flag = 1; } else putchar(c);
if (flag)
{
if (c != '*')
{
flag = 0;
if (k == 1) { putchar('*'); k = 0; continue; }
for (int i = 0; i< k/2; i++)
putchar('+');
k = 0;
}
}
}
This code does not work. I tried to swap those two if's:
char c = 0, flag = 0; int k = 0;
while ((c = getchar()) !='.')
{
if (flag)
{
if (c != '*')
{
flag = 0;
if (k == 1) { putchar('*'); k = 0; continue; }
for (int i = 0; i< k/2; i++)
putchar('+');
k = 0;
}
}
if (c == '*') { k++; flag = 1; } else putchar(c);
}
but after doing that symbols after single '*' are not printed, that is inputting "asf****f*d" I get "asf++f*"
Your second attempt had the best chance of success, but the flow of control got messed up due to your use of continue. Many people find comfort in this statement, but in this case it is just a bad goto. Please use else to escape your nested ifs; draw an NSD if you find this difficult. Currently, continue skips the putchar(c) in your second code sample, which explains the loss of the character following the single star.
There is another issue though; if the closing period is immediately preceded by a list of stars, then the replacement plusses will not be printed. This is caused by the fact that you save up all stars and print the replacing plusses all in one go. This 'buffering' demands a 'flush'. Though this is not difficult (print the pending plusses after the outer loop has finished), it does make your code messier. I strongly recommend to slightly change your algorithm. Instead of saving up stars, just print a single plus for every second star. This will make your code simpler and cleaner, and a 'flush' is no longer necessary.
I could of course give you a complete solution, but where's the fun in that?
Related
I have a char array that I get from the user and I need to return which is the longest word and which is the shortest, my problem is that my code doesn't recognize the last word because of my if term as it wont enter the else block for the last word because it wont recognize any spaces or new lines and I don't know how to fix it.
while (c != EOF)
{
counter++;
if (c != 32 && c != '\n') {
lengthCounter++;/*1*/
charHolder[i] = c;/*m*/
i++;/*1*/
} else {
if (lengthCounter/*1*/>= maxLenght/*3*/) {
maxLenght = lengthCounter;/*4*/
for (j = 0; j < lengthCounter + 1; j++) {
maxWord[j] = charHolder[j];/*cccc*/
}
lengthCounter = 0;
}
c = getchar();
I have tried c != EOF at the if statement but that didn't change anything.
One important thing is that I need to "finish" the input from the user with CTRL D.
I am reading the C programming language book Dennis M. Ritchie and
trying to solve this question:
Write a program to print a histogram of
the lengths of words in
its input. It is easy to draw the histogram with the bars horizontal; a vertical
orientation is more challenging.
I think my solution works, but the problem is that if I don't press EOF, the terminal won't show the
result. I know that the condition specifies that exactly, but I am
wondering whether there is any way to make the program terminate after
reading a single line? (Sorry if my explanation of the problem is a bit shallow. Feel free to ask more.)
#include <stdio.h>
int main ()
{
int digits[10];
int nc=0;
int c, i, j;
for (i = 0; i <= 10; i++)
digits[i] = 0;
//take input;
while ((c = getchar ()) != EOF) {
++nc;
if (c == ' ' || c=='\n') {
++digits[nc-1];
//is it also counting the space in nc? i think it is,so we should do nc-1
nc = 0;
}
}
for (i = 1; i <= 5; i++) {
printf("%d :", i);
for (j = 1; j <= digits[i]; j++) {
printf ("*");
}
printf ("\n");
}
// I think this is a problem with getchar()
//the program doesn't exit automatically
//need to find a way to do it
}
You could try to make something like
while ((c = getchar ()) != EOF && c != '\n') {
and then adding a line after the while loop to account for the last word:
if (c == '\n') {
++digits[nc-1];
nc = 0;
There is also another problem inside your program. ++digits[nc-1]; is correct, however, for the wrong reason. You should make it because an array starts at zero, i.e. if you have an array of length 10, it will go from 0 to 9, so you should count the length of the words and then add one to the position of the array length - 1 (as there are no words of length zero). The problem is that you are still counting the blank spaces or the newline characters inside the length of a word, so if you have two blank spaces after a word of length 4, the program will add to the array a word of length 5 + a word of length 1. To avoid this, you should do something like this:
while ((c = getchar ()) != EOF) {
if ((c == ' ' || c == '\n' || c == '\t') && nc > 0) {
++digits[nc-1]; // arrays start at zero
nc = 0;
}
else {
++nc;
}
}
In this piece of code I'm trying to check if a string (in my case the name of a club) is already entered from standard input. My goal is to avoid entering a name already present in the list, but it doesn't work.
Can someone help me please?
Thanks all.
gets(club[i].name);
if(i != 0){
for(left = 0; left < i; left++){
for(right = i; right > 0; right--){
outcome = strcmp(club[left].name, club[right].name);
if(outcome == 0){
printf("You already entered this team. Pick another one: \n");
gets(club[i].name);
}
}
}
}
i++;
break;
I'm not sure about the algo. (Besides, use fgets instead of gets)
You should compare against [i], not the other values.
This is simpler than the algo left/right:
int ok = 1;
for(int j = 0; j < i && ok ; j++){
ok = strcmp(club[j].name, club[i].name);
}
if ( ! ok) {
// ask again on the same 'i'
}
AFAIU, i is the last item, so j goes from 0 to i-1.
You don't need nested loops, because each input has already been checked against the previous ones. So when a new one comes, you only need to compare it with the previous values.
edit: If n is the number of items (item i is currently being input, but is not always the latest one), use that algo instead
int ok = 1;
for(int j = 0; j < n && ok ; j++){
ok = j == i || strcmp(club[j].name, club[i].name);
}
if ( ! ok) {
// ask again on the same 'i'
}
Just talk about your logic. Except for redundant comparisons, I think you need to reset the value of left and break inner loop.
Following your logic, the code should be:
gets(club[i].name);
if(i != 0){
for(left = 0; left < i; left++){
for(right = i; right > 0; right--){
outcome = strcmp(club[left].name, club[right].name);
if(outcome == 0){
printf("You already entered this team. Pick another one: \n");
gets(club[i].name);
left = 0;
break;
}
}
}
}
i++;
break;
I'm a complete beginner in C, and currently working through the exercises in the C Programming Language-book by Kernighan and Ritchie. This particular exercise is 1.13, where I'm trying to make a program that outputs a histogram based on the lengths of the words inputted. However, when compiling and running this piece of code, I receive the following error after hitting Enter in the console:
Illegal Instruction: 4
The code itself is definitely faulty and incomplete, but I was simply trying to test it here. The problem is I cannot figure out where this error is coming from. I'm using a Macbook and have tried to specify my OS-version during compilation to gcc, without this helping the problem.
#define WORD 0
#define NONWORD 1
int main(void)
{
int c, i, j;
int state;
int incrementer;
/* This solution only works for word-lengths below 20 characters.
Can be expanded/decreased by resizing wordLengths-array to any given length. */
int wordLengths[20];
while ((c = getchar()) != EOF) {
if (c == ' ' || c == '\t' || c == '\n'){
state = NONWORD;
} else {
state = WORD;
}
if (state == WORD) {
incrementer++;
}
if (state == NONWORD && incrementer != 0) {
wordLengths[incrementer-'1']++;
incrementer = 0;
}
}
for (i = 0; i < sizeof(wordLengths); i++) {
printf("%d |", i);
for (j = 0; j < wordLengths[i]; j++) {
putchar('=');
}
printf("\n");
}
printf("Hello world");
}
Debugger is your best friend. You would immediately realize that your incrementer isn't enough for counting which word is it at, or for being used as your array's index.
One of the possibilities would be to introduce a separate variable for counting words and writing measured length to corresponding member of your array
int wcnt = -1;
in the following way:
if (state == WORD) {
if(incrementer == 0)wcnt++;
incrementer++;
}
if (state == NONWORD && incrementer != 0) {
wordLengths[wcnt] = incrementer;
incrementer = 0;
}
and also use it for printf()ing the written sizes from the array members:
for (i = 0; i <= wcnt; i++){ … }
Here is what I want to do:
Read all characters from a '.c' file and store that into an array.
When a character from that array is '{', it will be pushed into a stack. And count of pushed characters will be increased by 1.
When a character from that array is '}', stack will pop and the count of popped characters will be increased by 1.
Compare those two counts to check whether there is a missing '{' or '}'
Here is my code:
int getLinesSyntax(char s[], int limit, FILE *cfile)
{
int i, c, push_count = 0, pop_count = 0;
int state = CODE;
int brackets[limit];
char braces[limit];
for(i = 0; i < 100; i++)
{
braces[i] = 0;
}
for(i = 0; i < limit - 1 && (c = getc(cfile)) != EOF && c != '\n'; i++)
{
s[i] = c;
if(s[i] == '{')
{
braces[0] = s[i];
//push(s[i], braces);
++push_count;
}
else if(s[i] == '}')
{
pop(braces);
++pop_count;
}
}
//Mor shiljih uyed array -n togsgold 0-g zalgana
if(c == '\n')
{
s[i] = c;
i++;
}
s[i] = '\0';
i = i -1; //Suuld zalgasan 0 -g toonoos hasna
if(c == EOF)
{
//just checking
for(i = 0; i < 100; i++)
{
printf("%d", braces[i]);
}
if(push_count != pop_count)
{
printf("%d and %d syntax error: braces", push_count, pop_count);
}
return -1;
}
else
{
return i;
}
}
Here is the output
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
The problems is:
Assignments inside the for loop is not working. (It's working when I put that outside of the loop)
I would like to know if there's something wrong with my code :).
There are several problems.
Lets go through it step by step
1) Your array initialization loop:
int brackets[limit];
char braces[limit];
for(i = 0; i < 100; i++)
{
braces[i] = 0;
}
You declare the array having size of limit but only initialize 100 items. Change 100 to limit to fully initialize it depending on the parameter of the function.
2) The conditional statement of the main for loop:
i < limit - 1 && (c = getc(cfile)) != EOF && c != '\n'
Although the first substatement is correct I have two remarks:
Firstly (c = getc(cfile)) != EOF might be one reason why the loop is never accessed and still everything is 000000.... Check if the file exists, the pointer is not NULL or other silent errors occured.
Secondly the c != '\n'. What if one of these characters occurs? In this case you won't continue with the next iteration but break out of the entire forloop. Remove it there and put it in the first line of the body like this:
if(c == '\n')
{
i -= 1; // to really skip the character and maintain the index.
continue;
}
3) s[i] = c;
Can you be certain, that the array is indeed sizeof limit?
4) Checking for curly braces
if(s[i] == '{')
{
braces[0] = s[i];
//push(s[i], braces);
++push_count;
}
else if(s[i] == '}')
{
pop(braces);
++pop_count;
}
You assign to braces[0] always, why?
5) Uninitialized access
if(c == '\n')
{
s[i] = c;
i++;
}
s[i] = '\0';
i = i -1; //Suuld zalgasan 0 -g toonoos hasna
You're now using the function-global variable i, which is never initialized properly for this block. What you do is to use a variable that is used basically everywhere ( which is basically also no problem from the memory point of view. ), but you rely on legacy values. Is this done by purpose? If no, reinitialize i properly. I have to ask this since i can't read your comments in code.
What I'm quite unhappy about is that you entirely rely on one variable in all the loops and statements. Usually a loop-index should never be altered from inside. Maybe you can come up with a cleaner design of the function like an additional index variable you parallelly increase without altering i. The additional index will be used for array access where appropriate whereas i really remains just a counter.
I think the problem is in this condition "c != '\n'" which is breaking the for loop right after the first line, before it reaches any brackets. And hence the output.
For the task of counting whether there are balanced braces in the data, the code is excessively complex. You could simply use:
int l_brace = 0;
int r_brace = 0;
int c;
while ((c = getchar()) != EOF)
{
if (c == '{')
l_brace++;
else if (c == '}')
r_brace++;
}
if (l_brace != r_brace)
printf("Number of { = %d; number of } = %d\n", l_brace, r_brace);
Of course, this can be confused by code such as:
/* This is a comment with an { in it */
char string[] = "{{{";
char c = '{';
There are no braces that mark control-of-flow statement grouping in that fragment, for all there are 5 left braces ({) in the source code. Parsing C properly is hard work.