Illegal Instruction: 4 in C-program - c

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++){ … }

Related

How do I store an array in three different ones based on delimiters

I want to split an input array into three different ones based on a / as a delimiter.
I have tried the (probably the naive) approach of storing an input string into different arrays by using getchar and while to read in the characters into an array and using a counter to count how many times a / appears.
Based on this number I would use:
if (slashcounter == 0) {
destinationarray[i++] = c;
}
to store it into the proper array. full implementation below.
please note that I try to do this using only stdio.h
#include <stdio.h>
char c;
char replace[80], toBeReplaced[80], input[80], testInput[80];
int i = 0;
int slashcounter = 0;
int main(){
puts("Enter a line of text: ");
while (( c = getchar()) != '\n'){
if (c == '/') {
slashcounter++;
}
if (slashcounter == 0) {
replace[i++] = c;
}
else if (slashcounter == 1) {
toBeReplaced[i++] = c;
}
else if (slashcounter == 2) {
input[i++] = c;
}
}
//debug purpose
puts("The arrays have the following content\n");
puts("replace[]:\n");
puts(replace);
puts("\n");
puts("toBeReplaced[]:\n");
puts(toBeReplaced);
puts("\n");
puts("input[]:\n");
puts(input);
printf("Slashcounter = %d\n",slashcounter);
return 0;
Unfortunately, what happens is: that the first word i.e. the word before the first slash is stored correctly but the other two are empty.
What have I done wrong here
the current output with the input this/test/fails
Enter a line of text:
this/test/fails
The arrays have the following content
replace[]:
this
toBeReplaced[]:
input[]:
Slashcounter = 2
Program ended with exit code: 0
p.s. I would also like to ensure that the /s are not in the output array.
Thank you for your help.
You have two immediate problems in your code, first you miss to add a null character to end each sub string, second you never reset the index to 0 when you read a /
Other problems are you do not check if you will write out of the arrays, and you do not not manages the EOF
You also test the value of slashcounter all the time, this is quite expensive for nothing, you can have 3 loops or use a pointer to point to the array to fill etc
There is also no reason to use global variables, all of them can be local in main
Example with minimal changes :
#include <stdio.h>
int main(){
int c;
char replace[80], toBeReplaced[80], input[80];
int i = 0;
int slashcounter = 0;
puts("Enter a line of text: ");
while (( c = getchar()) != '\n') {
if (c == EOF) {
fprintf(stderr, "unexpected EOF");
return -1;
}
if (c == '/') {
if (slashcounter == 0) {
replace[i] = 0;
}
else if (slashcounter == 1) {
toBeReplaced[i] = 0;
}
else if (slashcounter == 2) {
input[i] = c;
}
i = 0;
slashcounter++;
}
else if (slashcounter == 0) {
if (i != (sizeof(replace) - 2))
replace[i++] = c;
}
else if (slashcounter == 1) {
if (i != (sizeof(toBeReplaced) - 2))
toBeReplaced[i++] = c;
}
else if (slashcounter == 2) {
if (i != (sizeof(input) - 2))
input[i++] = c;
}
}
if (slashcounter == 0) {
replace[i] = 0;
toBeReplaced[0] = 0;
input[0] = 0;
}
else if (slashcounter == 1) {
toBeReplaced[i] = 0;
input[0] = 0;
}
else if (slashcounter == 2) {
input[i] = 0;
}
//debug purpose
puts("The arrays have the following content\n");
puts("replace[]:\n");
puts(replace);
puts("\n");
puts("toBeReplaced[]:\n");
puts(toBeReplaced);
puts("\n");
puts("input[]:\n");
puts(input);
printf("Slashcounter = %d\n",slashcounter);
return 0;
}
Note I use an int for c to handle EOF and I removed the useless array testInput
Compilation and execution :
pi#raspberrypi:/tmp $ gcc -pedantic -Wall -Wextra s.c
pi#raspberrypi:/tmp $ ./a.out
Enter a line of text:
this/test/fails
The arrays have the following content
replace[]:
this
toBeReplaced[]:
test
input[]:
fails
Slashcounter = 2

Condition using EOF in C

The code below is my answer to exercise 1-13 in K&R The C Programming Language, which asks for a histogram for the length of words in its input. My question is regarding EOF. How exactly can I break out of the while loop without ending the program entirely? I have used Ctrl-Z which I have heard is EOF on Windows, but this ends the program, instead of just breaking the while loop. How can I get to the for loop after the while loop without ending the file? This is a general question, not just with my code below but for all the code in K&R that uses: while ((c = getchar()) != EOF). Thanks in advance!
`
#include <stdio.h>
#define MAXLENGTH 20 /* Max length of a word */
#define IN 1 /* In a word */
#define OUT 0 /* Out of a word */
int main() {
int c, i, j, len = 0;
int lenWords[MAXLENGTH];
bool state = OUT;
for (i = 0; i < MAXLENGTH; ++i) {
lenWords[i] = 0;
}
c = getchar();
while (c != EOF) {
if (c != ' ' && c != '\n' && c != '\t') {
if (state == IN) {
lenWords[len - 1] += 1; /* a length 5 word is in subscript 4 */
len = 0;
}
state = OUT;
}
else {
state = IN;
}
if (state == IN) {
len += 1;
}
c = getchar();
}
/* Generating a histogram using _ and | */
for (i = 0; i < MAXLENGTH; ++i) { /* Underscores write over one another; not so efficient */
for (j = 0; j < lenWords[i]; ++j) {
putchar('_');
}
putchar('\n');
for (j = 0; j < lenWords[i]; ++j) {
putchar('_');
}
putchar('|');
printf("Length: %d, Frequency: %d", i + 1, lenWords[i]);
}
return 0;
}
I think your question belongs on another network.
Answers here: Equivalent to ^D (in bash) for cmd.exe?
No. CtrlD on *nix generates a EOF, which various
shells interpret as running exit. The equivalent for EOF on Windows
is CtrlZ, but cmd.exe does not interpret this
specially when typed at the prompt.
Ctrl+D to sends EOF to standard input and stops the read on *nix.
Have a look here.
You have to check whether you use *nix or windows.
On Windows, EOF is represented by Ctrl+Z, whereas on *nix EOF is represented by Ctrl+D

replace rows of n(n>=2) '*' symbols with n/2 '+' symbols

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?

Can't assign value to a variable inside a for loop

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.

Detecting combination of characters from input

My task is:
Write a program that reads input up to # and reports the number of times that the sequence ei occurs.
I wrote something that in most of the times works, but there are inputs when it dosent...
Like this input:(suppose to return 1)
sdlksldksdlskd
sdlsklsdks
sldklsdkeisldksdlk
#
number of combination is: 0
This is the code:
int main(void)
{
int index = 0;
int combinationTimes = 0;
int total = 0;
char userInput;
char wordChar[index];
printf("please enter your input:\n");
while ((userInput = getchar()) != '#')
{
if (userInput == '\n')
continue;
wordChar[index] = userInput;
index++;
total++;
}
for (index = 1; index < total; index++)
{
if (wordChar[index] == 'i')
{
if (wordChar[--index] == 'e')
{
combinationTimes++;
++index;
}
}
}
printf("number of combination is: %d", combinationTimes);
return 0;
}
Can you please tell me what am I not getting 1 using this input?
in the book he said to test it with "Receive your eieio award" and it worked...but after i played with it a little i see that not always.
It really doesn't seem necessary to read the file into an array. You just need to keep track of how many times ei is found before you read a # or reach EOF:
#include <stdio.h>
int main(void)
{
int c;
int ei_count = 0;
while ((c = getchar()) != EOF && c != '#')
{
if (c == 'e')
{
int c1 = getchar();
if (c1 == 'i')
ei_count++;
else if (c1 != EOF)
ungetc(c1, stdin);
}
}
printf("ei appeared %d times\n", ei_count);
return(0);
}
Testing (the program is called ei and is built from ei.c):
$ ei < ei.c
ei appeared 0 times
$ sed 1d ei.c | ei
ei appeared 1 times
$ sed 's/#/#/' ei.c | ei
ei appeared 4 times
$
The first one stops at the #include line, the second stops at the # in the comparison, and the third reads the entire file. It also gives the correct output for the sample data.
Analysing the code
Your primary problem is that you do not allocate any space for the array. Change the dimension of the array from index to, say, 4096. That'll be big enough for your testing purposes (but really the program should pay attention to the array and not overflowing it — but then I don't think the array is necessary at all; see the code above).
The next primary problem is that despite its name, getchar() returns an int, not a char. It can return any valid character plus a distinct value, EOF. So it must return a value that's bigger than a char. (One of two things happens if you use char. If char is a signed type, some valid character — often ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS — is also treated as EOF even though it is just a character. If char is an unsigned type, then no input matches EOF. Neither is correct behaviour.)
Fixing that is easy, but your code does not detect EOF. Always handle EOF; the data may be malformatted. That's a simple fix in the code.
A tertiary problem is that the printf() statement does not end with a newline; it should.
Your test condition here is odd:
if (wordChar[--index] == 'e')
{
combinationTimes++;
++index;
}
It's odd to use one pre-increment and one post-increment, but that's just a consistency issue.
Worse, though, is what happens when the character i appears in the input and is not preceded by e. Consider the line #include <stdio.h>: you start with index as 1; that is an i, so you decrement index, but wordChar[0] is not an e, so you don't increment it again, but the end of the loop does, so the loop checks index 1 again, and keeps on going around the loop testing that the i is i and # is not e for a long time.
There's no reason to decrement and then increment index; just use:
if (wordChar[index-1] == 'e')
combinationTimes++;
With those fixed, your code behaves. You trouble was largely that you were using an array that was not big enough (being size 0), and you were overwriting quasi-random memory with the data you were reading.
#include <stdio.h>
int main(void)
{
int index = 0;
int combinationTimes = 0;
int total = 0;
int userInput;
char wordChar[4096];
printf("please enter your input:\n");
while ((userInput = getchar()) != '#' && userInput != EOF)
{
if (userInput == '\n')
continue;
wordChar[index] = userInput;
index++;
total++;
}
printf("total: %d\n", total);
for (index = 1; index < total; index++)
{
if (wordChar[index] == 'i')
{
if (wordChar[index-1] == 'e')
combinationTimes++;
}
}
printf("number of combination is: %d\n", combinationTimes);
return 0;
}
Note that you could reasonably write the nested if as:
if (wordChar[index] == 'i' && wordChar[index-1] == 'e')
combinationTimes++;
change your wordChar array value.
int main(void)
{
int index = 0;
int combinationTimes = 0;
int total = 0;
char userInput;
//char wordChar[index]; // index = 0
char wordChar[255]; // should change the value of array.
printf("please enter your input:\n");
while ((userInput = getchar()) != '#')
{
if (userInput == '\n')
continue;
wordChar[index] = userInput;
index++;
total++;
}
for (index = 1; index < total; index++)
{
if (wordChar[index] == 'i')
{
if (wordChar[--index] == 'e')
{
combinationTimes++;
++index;
}
}
}
printf("number of combination is: %d", combinationTimes);
return 0;
}
or maybe you can use pointer and then use malloc and realloc.

Resources