I'm trying to code a very simple brainfuck interpreter in C, and I run into problems while trying to outprint certain characters by what I understand.
This is all my code:
#include <stdio.h>
int bla(char tabukaz[30000], int ukaz, int num) {
int sum = 0;
int index = ukaz;
while (sum > -1) {
index -= num;
if (tabukaz[index] == ']')
sum += num;
else if (tabukaz[index] == '[')
sum -= num;
}
return index;
}
int main () {
int tab[30000];
int tabukaz[30000];
int c;
int i = 0; int ukaz = 0;
unsigned char ch;
for (int i = 0; i < 30000; i++) {
tab[i] = 0;
tabukaz[i] = 0;
}
while ((c=getchar()) != EOF) {
ch = (unsigned char)c;
if (ch == '>' || ch == '<' || ch == '+' || ch == '-' || ch == '.' || ch == '[' || ch == ']')
{
tabukaz[ukaz] = ch;
}
switch (ch) {
case '>': i++; break;
case '<': i--; break;
case '+': tab[i]++;break;
case '-': tab[i]--; break;
case '.': putchar(tab[i]); break;
case '[':
if (tab[i]==0) {
ukaz = bla(tabukaz, ukaz, -1);
}
break;
case ']':
if (tab[i]!=0) {
ukaz = bla(tabukaz, ukaz, 1);
}
break;
default:
break;
}
ukaz++;
}
return 0;
}
This is the input in question (I tried to avoid the other text in the actual input (keep in mind everything down here is part of the input, even the unnecessary text) We were provided with a make file which will write the output into a text file, and compare it to a predefined text, the problem is my text file comes out as a binary file and I cant figure out why. The problem may be hidden in how I handle [ and ] as I didn't have that problem in the earlier tests without them
+++++ +++++ initialize counter (cell #0) to 10
[ use loop to set 70/100/30/10
> +++++ ++ add 7 to cell #1
> +++++ +++++ add 10 to cell #2
> +++ add 3 to cell #3
> + add 1 to cell #4
<<<< - decrement counter (cell #0)
]
> ++ . print 'H'
> + . print 'e'
+++++ ++ . print 'l'
. print 'l'
+++ . print 'o'
> ++ . print ' '
<< +++++ +++++ +++++ . print 'W'
> . print 'o'
+++ . print 'r'
----- - . print 'l'
----- --- . print 'd'
> + . print '!'
> . print '\n'
As a suggestion made by somebody I did this:
while ((c=getchar())!=EOF) {
ch = (unsigned char)c;
if (ch == '>' || ch == '<' || ch == '+' || ch == '-' || ch == '.' || ch == '[' || ch == ']')
{
tabukaz[ukaz]=ch;
stukaz++;
}
}
while (stukaz>0) {
switch (tabukaz[ukaz]) {
case '>': i++; break;
case '<': i--; break;
case '+': if(tab[i]==255) tab[i] = 0;
else tab[i]++;
break;
case '-': if (tab[i]==0) tab[i] = 255;
else tab[i]--;
break;
case '.': printf ("%c", tab[i]); break;
case '[':
if (tab[i]==0) {
ukaz = bla(tabukaz, ukaz, -1);
}
break;
case ']':
if (tab[i]!=0) {
ukaz = bla(tabukaz, ukaz, 1);
}
break;
default: break;
}
stukaz--;
ukaz++;
}
However the problem now extends to the tests before that, as it even outputs those as binary files, I'm thinking there's something wrong with the [ and ] code and thus it doesn't increment the fields properly printing unwanted characters, how this extended to tests without them only when putting another loop around it I have no idea.
EDIT: the problem with the above loop is not the while loop not going trough, the problem is that it will never get into the switch, any solution to that?
The test is wrong while scanning for a matching bracket.
while (sum > -1) {
index -= num;
if (tabukaz[index] == ']')
sum += num;
else if (tabukaz[index] == '[')
sum -= num;
}
You set num to 1 for a backwards scan, but to -1 for a forward scan.
case '[':
if (tab[i]==0) {
ukaz = bla(tabukaz, ukaz, -1);
}
break;
case ']':
if (tab[i]!=0) {
ukaz = bla(tabukaz, ukaz, 1);
}
break;
So the test should be (sum != 0) so it stops when the brackets are balanced from either direction. Of course, sum is initialized to 0, so I recommend a do { ... } while(); loop so the test is at the end.
Also, remember that you're incrementing the instruction pointer at the end of the loop.
ukaz++;
So you may want to set the pointer to bla(...) - 1, so the increment puts the pointer in the correct place.
You might also like to look at my own brainfuck interpreter, which is very similar to yours. One of my reviewers there gives an excellent explanation of optimizing the loop execution with a jump table.
Related
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(){
char S[10007];
scanf("%[^\n]", S); getchar();
int i = 0;
char u;
while(S[i]){
u = toupper(S[i]);
if(strcmp(u, "I") == 0){
u = '1';
}
else if(strcmp(u, "R") == 0){
u = '2';
}
else if(strcmp(u, "E") == 0){
u = '3';
}
else if(strcmp(u, "A") == 0){
u = '4';
}
else if(strcmp(u, "S") == 0){
u = '5';
}
else if(strcmp(u, "G") == 0){
u = '6';
}
else if(strcmp(u, "T") == 0){
u = '7';
}
else if(strcmp(u, "B") == 0){
u = '8';
}
else if(strcmp(u, "P") == 0){
u = '9';
}
else if(strcmp(u, "O") == 0){
u = '0';
}
printf("%s", u);
i++;
}
return 0;
}
I got a case where i need to make an inputted string uppercase then change some of the uppercase alphabet to the following number, (example input: im waterswell, the otuput: 1M W4T325W33L) so i created the program but it returns to following error: invalid conversion from 'char' to 'const char*' [-fpermissive]. Can anyone help me? thank you
strcmp is used to compare strings, not single characters. Use simply if (u == 'I') and use that everywhere you have strcmp (notice the quote change - we want a character, not a string literal).
Also, printf("%s", u); is wrong, you need %c to print a char.
What source are you learning C++ from?
This is more like what I would expect from C++ :
#include <string>
#include <iostream>
#include <unordered_map>
// lookup table
static std::unordered_map<char, char> mapping
{
{'I','1'}, {'i','1'},
{'R','2'}, {'r','2'},
{'E','3'}, {'e','3'},
{'A','4'}, {'a','4'},
{'S','5'}, {'s','5'},
{'G','6'}, {'g','6'},
{'T','7'}, {'t','7'},
{'B','8'}, {'b','8'},
{'O','9'}, {'o','9'},
{'U','0'}, {'u','0'},
};
int main()
{
//std::string input;
//std::cin >> input;
std::string input{ "TESTcase" };
for (const char c : input)
{
// check if key can be found
auto it = mapping.find(c);
if (it == mapping.end())
{
// if not cast to upper, std::toupper doesn't return a char
// so cast it.
std::cout << static_cast<char>(std::toupper(c));
}
else
{
// structured binging
const auto&[key, value] = *it; // *it refers to an key value pair in the map
std::cout << value;
}
}
return 0;
}
To compare chars, you use == and a character literal, e.g.
if (u == 'O')
.
Also printing a single char with the format specifier for a null terminated string (%s) results in undefined behaviour.
You could just modify the inpur array instead and print everything in one go...
Since you tagged this C++, I'll present a C++ solution:
int main() {
char S[10007];
std::scanf("%[^\n]", S); getchar();
int i = 0;
// modify S to hold the content we want to print
for (auto& c : S)
{
if (c == '\0')
{
// end of string
break;
}
c = std::toupper(c);
switch (c)
{
case 'I':
c = '1';
break;
case 'R':
c = '2';
break;
case 'E':
c = '3';
break;
case 'A':
c = '4';
break;
case 'S':
c = '5';
break;
case 'G':
c = '6';
break;
case 'T':
c = '7';
break;
case 'B':
c = '8';
break;
case 'P':
c = '9';
break;
case 'O':
c = '0';
break;
}
}
std::printf("%s\n", S);
}
My code runs well to my surprise!!
The only problem is that whenever I use a bracketed infix input it comes out a 'J' at the end of postfix expression !! Any suggestions??
Here the algorithm is the basic one all expressions are getting converted and all is right but the tailing 'J' is i just cann't understand !! Suggestions??
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
#define MAX 50
char stack[MAX];
int top = -1;
void push(char element)
{
stack[++top] = element;
}
char pop()
{
return(stack[top--]);
}
char tope()
{
return(stack[top]);
}
int prec(char c)
{
switch(c){
case '+':
case '-' : return 1;
break;
case '*' :
case '/' : return 2;
break;
default:
return 0;
break;
}
}
int main()
{
char post[MAX],in[MAX],ch,element;
printf("Infix expression : ");
scanf("%s",in);
int i=0,k=0;
in[strlen(in)] = ')';
push('(');
while((ch = in[i++]) != '\0')
{
if(isalnum(ch))
post[k++] = ch;
if(ch == '(')
push(ch);
if(ch == ')')
{
while(tope() != '(')
{
post[k++] = pop();
}
pop();
}
if(ch == '+' || ch =='-' || ch == '*' || ch == '/')
{
while(prec(ch) <= prec(tope()))
{
post[k++] = pop();
}
push(ch);
}
}
post[k] = '\0';
printf("%s",post);
return 0;
}
in[strlen(in)] = ')';
overwrites the nul-terminating character, which explains strange chars when printing (printing stops only when meeting another nul char by luck: undefined behaviour which may even lead to a crash if no nul char is found in the in 50-byte buffer)
You have to shift it, for instance like this:
int l = strlen(in);
in[l] = ')';
in[l+1] = '\0';
Note: you have to store the length of your string in l instead of calling strlen(in) twice not only because of the performance loss but, because putting the parenthesis means that strlen doesn't work properly until you null-terminate.
(also you probably want to protect your scanf like this: scanf("%48s",in); so you're sure to have enough room for the extra parenthesis for your 50-size buffer, even compatible with your macro definition, see scanf: template with macro (#define constant) inside)
I'm new to C and I've been working on this homework problem for about 2 hours to no avail. I'm attempting to create a program that takes an alphabetic phone number (ie; CALLATT or 1-800-COL-LECT) and turns it into the number form (2255288 or 1-800-265-5328). No matter what I put for input, though, I always get -4197680 for my output.
int main(void){
int c=0, len, a[len];
char n[len];
printf("Enter phone number: \n");
scanf("%c", n);
len = sizeof(n) / sizeof(n[0]);
while (len > c){
if (n[c] == 'A' || n[c] == 'B' || n[c] == 'C'){
a[c] = 2;
c++;
}
else if (n[c] == 'D' || n[c] == 'E' || n[c] == 'F'){
a[c] = 3;
c++;
}
else if (n[c] == 'G' || n[c] == 'H' || n[c] == 'I'){
a[c] = 4;
c++;
}
else if (n[c] == 'J' || n[c] == 'L' || n[c] == 'L'){
a[c] = 5;
c++;
}
else if (n[c] == 'M' || n[c] == 'N' || n[c] == 'O'){
a[c] = 6;
c++;
}
else if (n[c] == 'P' || n[c] == 'Q' || n[c] == 'R' || n[c] == 'S'){
a[c] = 7;
c++;
}
else if (n[c] == 'T' || n[c] == 'U' || n[c] == 'V'){
a[c] = 8;
c++;
}
else if (n[c] == 'W' || n[c] == 'X' || n[c] == 'Y' || n[c] == 'Z'){
a[c] = 9;
c++;
}
else {
a[c] = n[c];
c++;
}
}
printf("%d\n", a);
return 0;
}
EDIT: Revised. There were many comments pointing out problems, here is my answer which works with a reasonable length phone number. It skips any non-dialing characters, such as '-' which is not part of a phone number.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(void){
int k, d, e, len;
char dial[20], entry[20] = {0};
printf("Enter phone number: ");
fgets(entry, 19, stdin);
len = strlen(entry);
d = 0; // dial string index of output
for (e=0; e<len; e++) { // entry string index of input
k = entry[e];
switch (toupper(k)) {
case 'A': case 'B': case 'C': dial[d++] = '2'; break;
case 'D': case 'E': case 'F': dial[d++] = '3'; break;
case 'G': case 'H': case 'I': dial[d++] = '4'; break;
case 'J': case 'K': case 'L': dial[d++] = '5'; break;
case 'M': case 'N': case 'O': dial[d++] = '6'; break;
case 'P': case 'Q': case 'R': case 'S': dial[d++] = '7'; break;
case 'T': case 'U': case 'V': dial[d++] = '8'; break;
case 'W': case 'X': case 'Y': case 'Z': dial[d++] = '9'; break;
default:
if (isdigit(k) || k=='*' || k=='#') dial[d++] = k;
}
}
dial[d] = 0; // terminate string
printf("Dial %s\n", dial);
return 0;
}
Here is some code:
char buf[32];
sscanf("%31s", buf);
size_t i;
for (i = 0; i < sizeof(buf) && buf[i]; ++i)
{
switch (buf[i])
{
case 'A': case 'B': case 'C':
buf[i] = '2'; break; // Note: character literal, not integer
case 'D': case 'E': case 'F':
buf[i] = '3'; break;
....
}
}
printf("%s", buf);
If you have a Posix-compliant library, you can use dynamic allocation:
char *buf;
scanf("%ms", &buf); //scanf would allocate memory
for (i = 0; buf[i]; ++i)
{
.....
}
printf("%s", buf);
free(buf);
There are so many problems in your code, it will almost need a re-write to make it work. I think you should start something small. Make sure it works before adding more functionality. I would suggest dividing the code in main into three sections -- reading the phone number, converting phone number and printing the converted phone number.
Here's a skeletal program that captures those three steps.
#define SIZE 50
void readPhoneNumber(char phoneNumber[])
{
}
void convertTextToNumber(char phoneNumber[], char dialedNumber[])
{
}
void printPhoneNumber(char phoneNumber[])
{
}
int main(void)
{
char phoneNumber[SIZE];
char dialedNumber[SIZE];
readPhoneNumber(phoneNumber);
convertTextToNumber(phoneNumber, dialedNumber);
printPhoneNumber(dialedNumber);
}
Now, you can start fleshing out the functions. For example, readPhoneNumber can be implemented as:
void readPhoneNumber(char phoneNumber[])
{
printf("Enter phone number: \n");
fgets(phoneNumber, SIZE, stdin);
}
printPhoneNumber can be implemented as:
void printPhoneNumber(char phoneNumber[])
{
printf("%s\n", phoneNumber);
}
I'll leave you to work out the implementation of convertTextToNumber.
Here you have undefined behavior, len is not initialized.
int c=0, len, a[len];
char n[len];
Use instead a constant value instead, i bet the phone number in your country has some kind of maximum length.
This way to read from the keyboard is not recommended, scanf does not check for length of string so you can do a faceroll on the keyboard and your program will crash. Instead use fgets( ) to read from stdin then go through the string char by char skipping the included \n
printf("Enter phone number: \n");
scanf("%c", n);
This makes no sense, you calculate the sizeof n i.e. of the integer that holds n. If you want the length of the string use strlen( n ); btw try to use more descriptive variable names.
len = sizeof(n) / sizeof(n[0]);
Instead of
while (len > c){
why not use a normal for-loop ? you seem to increment c++ everywhere.
this here will not do what you expect it to do
printf("%d\n", a);
but you assign 'a' integers e.g.
a[c] = 2;
printf can not magically print a number of your array, instead you want to print out is a string with the numbers. the ascii value of a digit is 48 + digit. e.g. '0' is 48, by knowing this have a character buffer and add the ascii values to it. make sure it ends with \0 which is end of string. then print out the string
buf[c++] = 48 + digit;
...
buf[c] = '\0';
puts( buf );
Can anyone tell me whats wrong with the following code that's suppose to remove comments and strings from an input (but not comments that's why it recognizes comments)? This is related to a prior question of mine: Removing comments with a sliding window without nested while loops
#include <stdio.h>
int main()
{
int c, c1 = 0, c2 = 0 ,state = 0, next = 0;
while(1)
{
switch(state)
{
case 0: next = ((c2 == '*' && c1 == '/') ? 1 : (c2 == '\"') ? 2 : (c2 == '/' && c1 == '/') ? 3 : (c2 == '\'') ? 4: 0); break;
case 1: next = ((c2 == '/' && c1 == '*') ? 0 : 1); break;
case 2: next = ((c2 == '\"' && c1 != '\\') ? 0 : 2); break;
case 3: next = ((c2 == '\n') ? 0 : 3); break;
case 4: next = ((c2 == '\'' && c1 != '\\') ? 0 : 4); break;
default: next = state;
}
c = getchar(); if( c < 0) break;
c1 = c2; c2 = c; // slide window
if(state == 1)
{
if(c2 == '*')
{
c = getchar();
c1 = c2; c2 = c;
if(c2 != '/')
putchar(c1);
}
else
putchar(c2);
}
else if(state == 2)
{
if(c2 != '"' || (c2 == '\"' && c1 != '\\'))
putchar(c2);
}
else if(state == 3)
{
putchar(c2);
}
else
state = next;
// c2 is the current input byte and c1 is the previous input byte
}
return 0;
}
I don't think you actually need a sliding window for your task of removing C and C++ comments. You can expand your state machine to include a few additions states for tracking escapes, etc... With more states the code gets a bit bigger, but it might make it conceptually simpler since you only have one state to track. So converting the spirit of your code to the new state machine formula I'd suggest, you get the code below (and I also agree with Basile's suggestion of using enums and included it).
#include <stdio.h>
int main()
{
enum {
START, SLASH,
STRING, CHAR, STRING_ESCAPE, CHAR_ESCAPE,
SINGLE_LINE_COMMENT, MULTI_LINE_COMMENT, MULTI_LINE_END,
} state = START;
int c;
while ((c = getchar()) != EOF) {
switch (state) {
case START:
state_START:
if (c == '/') { state = SLASH; break; }
putchar(c);
if (c == '\"') state = STRING;
else if (c == '\'') state = CHAR;
break;
case SLASH:
if (c == '/') state = SINGLE_LINE_COMMENT;
else if (c == '*') state = MULTI_LINE_COMMENT;
else { state = START; goto state_START; }
break;
case STRING:
putchar(c);
if (c == '"') state = START;
else if (c == '\\') state = STRING_ESCAPE;
break;
case CHAR:
putchar(c);
if (c == '\'') state = START;
else if (c == '\\') state = CHAR_ESCAPE;
break;
case SINGLE_LINE_COMMENT:
if (c == '\n') state = START;
break;
case MULTI_LINE_COMMENT:
state_MULTI_LINE_COMMENT:
if (c == '*') state = MULTI_LINE_END;
break;
case STRING_ESCAPE:
putchar(c);
state = STRING;
break;
case CHAR_ESCAPE:
putchar(c);
state = CHAR;
break;
case MULTI_LINE_END:
if (c == '/') state = START;
else { state = MULTI_LINE_COMMENT; goto state_MULTI_LINE_COMMENT; }
break;
}
}
return 0;
}
just to give you an advice without knowing your purposes... Did you thought about regular expressions to solve your problem? It is may faster and your code will be cleaner, assuming you understand regular expressions.
I found a neat site for your problem by the way... It explains how to get those comments out of the code...
How get comments with regex
And here is a library for regex in C.
I new at solving problems using C , I am trying to solve a SPOJ problem on
complicated Expression
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void removeBrackets(char *string , int position1 , int position2);
int main()
{
char exp[]="(a+b)-(c-d)-(e/f)";
char ops[]={'/','*','+','-','(',')','\0'};
char found[50][5];
int stack[3];
int i,j , k =0;
int l = (int)strlen(exp);
int lExp = l ;
char *p = exp ;
// //remove external brackets
// while (*(p+0)=='(' && *(p+strlen(p)-1)==')')
// removeBrackets(exp, 0, ((int)strlen(p)-1));
printf("expression : %s\n",exp);
printf("operators : %s\n",ops);
//find the operators and their location
l = 0 ;
for(i=0;i<lExp;i++)
{
for(j=0;j<strlen(ops);j++)
{
if(exp[i]==ops[j])
{
found[l][2]='N';
found[l][0]=i;
found[l][1]=ops[j];
if (exp[i-2]=='(' && exp[i+2]==')')
{
found[l][2]='Y';
found[l][3]=exp[i-3];
found[l][4]=exp[i+3];
}
if (found[l][1]=='(')
{
stack[k] = found[l][0];
k++;
}
else if(found[l][1]==')')
{
stack[k] = found[l][0];
if (stack[0] == 0 && stack[1] == lExp-1)
{
removeBrackets(exp, 0, (int)strlen(exp)-1);
break ;
}
removeBrackets(exp, stack[k-1], stack[k]);
//stack[k] = -1 ;
//stack[k-1] = -1 ;
k--;
}
printf("found '%c' at '%d' and within brackets: %c\n",found[l][1],found[l][0],found[l][2]);
l++;
}
}
}
//find where brackets are the corresponding sign in the brackets
for (i=0; i<l-1; i++)
{
if(found[i][2]=='Y')
{
//find higher precedence operators present nearby , and if their precedence is lower , then remove the brackets ,else keep the brackets
//1-find the operator inside the brackets
switch (found[i][1])
{
case '/':
printf("\nfound '/' within brackets");
removeBrackets(exp, found[i][0]-2, found[i][0]+2);
//remove the brackets
break;
case '*':
printf("\nfound '*' within brackets");
if (found[i][3] == '/' || found[i][4] == '/')
break ;
else
removeBrackets(exp, found[i][0]-2, found[i][0]+2);
break;
case '+':
printf("\nfound '+' within brackets");
if (found[i][3] == '/' || found[i][4] == '/' || found[i][3] == '*' || found[i][4] == '*' )
break ;
else
removeBrackets(exp, found[i][0]-2, found[i][0]+2);
break;
case '-':
printf("\nfound '-' within brackets");
if (found[i][3] == '/' || found[i][4] == '/' || found[i][3] == '*' || found[i][4] == '*' || found[i][4] == '+' || found[i][3] == '+')
break ;
else
removeBrackets(exp, found[i][0]-2, found[i][0]+2);
break;
default:
break;
}
}
}
printf("\nstring modified : %s",exp);
}
void removeBrackets(char *string, int position1 , int position2)
{
char *p = string;
char *newString = (char *)malloc(strlen(string -1));
int i = 0 , j =0 ;
for (i = 0 ; i <strlen(string); i++)
{
if (i == position1 || i == position2)
continue ;
else
{
newString[j] = *(p+i);
j++ ;
}
}
newString[j]='\0';
strcpy(string, newString);
printf("\n-----after removing brackets :- %s\n",newString);
free(newString);
}
What i am doing is , scanning all the words , then storing the found operators and brackets in an array 'Found' , stack is an array to check the sequence of '(' and ')' and 'ops' is an array to store all possible operators and brackets ,
then , if an operator is found within the brackets , then depending on the precendence of operators at left and right , brackets are removed .
But , after trying a lot , i am not able to come up with solution to remove brackets , for all test cases .
I searched on internet , they have used tree to solve this problem .
Can anybody please suggest some changes in my code to solve out the problem ..??
or is it that , the problem cannot be solved without trees ??