Understanding why the newline is caught on the next iteration - c

I wrote the following code:
int VALUE = 10;
int counter = 0;
char c;
while (true) {
if(scanf("%c", &c) != 1) {
return NULL;
}
if (c == '\n') {
break;
}
if (counter % VALUE < VALUE - 1) {
num[counter] = c;
counter++;
} else {
char* temp = (char*) malloc((counter + MAX_VALUE)*sizeof(char));
if (temp == NULL) {
return NULL;
}
for (int i = 0; i < counter; i++) {
temp[i] = num[i];
}
free(num);
num = temp;
num[counter] = c;
counter++;
}
}
printf("counter = %d\n",counter);
It doesn't really matter what it does but I have some problem with the counter. For some reason, when I insert 9876.54321 (newline at the end), It does not enters into the if (c == '\n') { break; } block when it scanfs \n, only on the next iteration. The length of 9876.54321 is 10 but it will print 11. What is the reason? I also tried to switch to getchar() but I get the same thing.

Here:
if(scanf("%c", &c) != 1) {
%c in scanf leaves the leading and following whitespace in the input buffer.
To fix this, don't use scanf. Use getchar or getc instead. Instead of using c == '\n', use isspace(c).
Don't do char c. You can't check for EOF if you do that. Instead, use int c.
Full code sample:
int VALUE = 10;
int counter = 0;
int c;
while (true) {
c = getchar();
if (isspace(c) || c == EOF) {
break;
}
if (counter % VALUE < VALUE - 1) {
num[counter] = c;
counter++;
} else {
char* temp = (char*) malloc((counter + MAX_VALUE)*sizeof(char));
if (temp == NULL) {
return NULL;
}
for (int i = 0; i < counter; i++) {
temp[i] = num[i];
}
free(num);
num = temp;
num[counter] = c;
counter++;
}
}
printf("counter = %d\n",counter);

Related

String Pattern Matching in C

I was trying this pattern matching method in C but whenever I give all the input, the vscode terminal waits for a while and just stops the program without any warnings/message. Can anyone point to what is wrong here?
#include <stdio.h>
#include <string.h>
int main()
{
char STR[100], PAT[100], REP[100], ANS[100];
int i, m, j, k, flag, slP, slR, len;
i = m = k = j = flag = len = 0;
printf("\nMain String: ");
gets(STR);
printf("\nPattern String: ");
gets(PAT);
slP = strlen(PAT);
printf("\nReplace String: ");
gets(REP);
slR = strlen(REP);
while (STR[i] != '\0')
{
if (STR[i] = PAT[j])
{
len = 0;
for (k = 0; k < slP; k++)
{
if (STR[k] = PAT[k])
len++;
}
if (len == slP)
{
flag = 1;
for (k = 0; k < slR; k++, m++)
ANS[m] = REP[k];
}
}
else
{
ANS[m] = STR[i];
m++;
i++;
}
}
if (flag == 0)
{
printf("\nPattern not found!");
}
else
{
ANS[m] = '\0';
printf("\nResultant String: %s\n", ANS);
}
return 0;
}
There are multiple problems in the code:
using gets() is risky, this function was removed from the C Standard because it cannot be used safely.
if (STR[i] = PAT[j]) copied the pattern to the string. You should use:
if (STR[i] == PAT[j])
similarly, if (STR[k] = PAT[k]) is incorrect. You should compare PAT[k] and STR[i + k]:
if (STR[i + k] == PAT[k])
you should test for buffer overflow for the output string as replacing a short string by a larger one may produce a string that will not fit in ANS
you do not increment i properly.
Here is a modified version:
#include <stdio.h>
int getstr(const char *prompt, char *dest, int size) {
int c, len = 0;
printf("%s", prompt);
while ((c = getchar()) != EOF && c != '\n') {
if (len + 1 < size)
dest[len++] = c;
}
if (size > 0)
dest[len] = '\0';
printf("\n");
if (c == EOF && len == 0)
return -1;
else
return len;
}
int main() {
char STR[100], PAT[100], REP[100], ANS[100];
int i, m, k, flag;
if (getstr("Main String: ", STR, sizeof STR) < 0)
return 1;
if (getstr("Pattern String: ", PAT, sizeof PAT) < 0)
return 1;
if (getstr("Replace String: ", REP, sizeof REP) < 0)
return 1;
i = m = flag = 0;
while (STR[i] != '\0') {
if (STR[i] == PAT[0]) { // initial match
// compare the rest of the pattern
for (k = 1; PAT[k] != '\0' && PAT[k] == STR[i + k]; k++)
continue;
if (PAT[k] == '\0') { // complete match
flag = 1;
// copy the replacement string
for (k = 0; REP[k] != '\0'; k++) {
if (m + 1 < sizeof ANS)
ANS[m++] = REP[k];
}
i += k; // skip the matching characters
continue;
}
}
// otherwise copy a single character
if (m + 1 < sizeof ANS)
ANS[m++] = STR[i];
i++;
}
ANS[m] = '\0';
if (flag == 0) {
printf("Pattern not found!\n");
} else {
printf("Resultant String: %s\n", ANS);
}
return 0;
}

passing char array to function from scanf in c

I have following function in c code
void analyze_text(char text[]) {
...
for (int i = 0; i < text_length || text[i] != '\0'; i++) {
...
}
}
In main function i would like to pass some string to it. If i do something like this
char text[4000] = "some text here";
analyze_text(text);
this is cool and do the goal, but i would like to have some user input present and I am not sure how to get char[] out of it. I tried following 2 and none of them seemed to work:
char text[4000];
scanf("%s",text);
analyze_text(text);
OR
char text[4000];
int c;
int count=0;
c = getchar();
count = 0;
while ((count < 4000) && (c != EOF)) {
text[count] = c;
++count;
c = getchar();
}
analyze_text(text);
I know that the first one should return pointer to char array, but second one should return char array itself, or not?
Its been like 10 years since i havent been working with c/c++. Can anybody give me some hint please?
update (whole function):
void analyze_text(char text[]) {
int printable_text_length = 0;
int text_length = strlen(text);
int word_count = 0;
int sentence_count = 0;
int in_sentence = 0;
int in_word = 0;
int count[ASCII_SIZE] = { 0 };
for (int i = 0; i < text_length || text[i] != '\0'; i++) {
int c = text[i];
if (!isspace(c)) {
printable_text_length++;
}
if (isalpha(c)) {
in_word = 1;
in_sentence = 1;
count[tolower(c)]++;
}
if (text[i] == ' ' && text[i + 1] != ' ' && in_word==1) {
word_count++;
in_word = 0;
}
if (text[i] == '.' && in_sentence==1) {
sentence_count++;
in_sentence = 0;
}
}
if (in_word == 1) { word_count++; }
if (in_sentence == 1) { sentence_count++; }
char charIndexes[ASCII_SIZE];
for (int i = 97; i <= 122; i++) {
charIndexes[i] = i;
}
for (int i=97; i <= 122; i++) {
for (int j = i + 1; j <= 122; j++) {
if (count[i] > count[j]) {
int temp = count[j];
count[j] = count[i];
count[i] = temp;
int temp2 = charIndexes[j];
charIndexes[j] = charIndexes[i];
charIndexes[i] = temp2;
}
}
}
...printf...
}
The issue with
char text[4000];
scanf("%s",text);
analyze_text(text);
is that scanf identifies space-separated chunks, so you'll only read the first one.
In order to read up to a whole line from the user, try fgets:
char text[4000];
fgets(text, 4000, stdin);
analyze_text(text);
You may want to check the return value of fgets for error detection.
You can use dyanamic array of char to pass it into the function.
Here is the code
#include <stdio.h>
#include <stdlib.h>
void analyze_text(char* text) {
for (int i = 0; text[i] != '\0'; i++) {
printf("%c\n",text[i] );
}
}
int main() {
char* text = (char *)malloc(4000 * sizeof(char));
scanf("%s", text);
analyze_text(text);
return 0;
}
and here is the output with input = 'abhishek'
a
b
h
i
s
h
e
k
remember that strlen in dyanamc array will not give the length of input array.

How can I get my Lexical analyzer program to print out more than just seperators?

Im writing a Lexical analyzer to read from a file and describe the text as either identifiers, keywords, separators, or operators. For some reason I am only able to output the separators, unless I delete or comment out the while loop with the print statement for the separators. When I delete that, the program prints out everything else correctly, skipping over the separators.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<ctype.h>
int isKeyword(char buffer[]){
char keywords[32][10] = {"auto","break","case","char","const","continue","default",
"do","double","Else","enum","Function","Float","for","goto",
"If","Integer","long","register","Return","short","signed",
"sizeof","static","struct","switch","typedef","union",
"DOWhile","void","Write","while"};
int i, flag = 0;
for(i = 0; i < 32; ++i){
if(strcmp(keywords[i], buffer) == 0){
flag = 1;
break;
}
}
int k, flag2 = 0;
for (k = 0; k<32; ++k){
if(strcmp(keywords[i], buffer) == 0){
flag2 = 1;
break;
}
}
return flag;
return flag2;
}
int main(){
char ch, buffer2[15], operators[] = "+-*/%=";
char ch2, buffer[15], seperators[] = "{}(),;";
FILE *fp;
int i,k,j=0;
fp = fopen("input.txt","r");
if(fp == NULL){
printf("error while opening the file\n");
exit(0);
}
while((ch = fgetc(fp)) != EOF){
for(i = 0; i < 6; ++i){
if(ch == operators[i])
printf("%c is operator\n", ch);
while((ch2 = fgetc(fp)) != EOF){
for(k = 0; k < 6; ++k){
if(ch2 == seperators[k])
printf("%c is seperator\n", ch2);
}
}
if(isalnum(ch)){
buffer[j++] = ch;
}
else if((ch == ' ' || ch == '\n') && (j != 0)){
buffer[j] = '\0';
j = 0;
if(isKeyword(buffer) == 1)
printf("%s is keyword\n", buffer);
else
printf("%s is indentifier\n", buffer);
}
}
}
fclose(fp);
return 0;
}
The problem seems to be the second while loop containing the separator instructions, but I cant seem to figure out how to print that along with everything else.
I think this may help.There is no reason to create an additional char ch, or the buffer, when creating the separators. Just add it onto the end of the previous line. I just split it with a comma.This will clean your code up and allow you to keep the separators with the rest of the while loop code.
#include <stdio.h>
#define KEY 32
#define BUFFER_SIZE 15
int isKeyword(char buffer[])
{
char keywords[KEY][10] = { "auto","break","case","char","const","continue","default", "do","double","else","enum","extern","float","for","goto",
"if","int","long","register","return","short","signed", "sizeof","static","struct","switch","typedef","union", "unsigned","void","volatile","while"};
int i, flag = 0;
for (i = 0; i < KEY; ++i)
{
if (strcmp(keywords[i], buffer) == 0)
{
flag = 1;
break;
}
}
return flag;
}
int main()
{
char ch, buffer[BUFFER_SIZE], operators[] = "+-*/%=", separators[] = "(){}[]<>,";
FILE *fp;
int i, j = 0;
fp = fopen("Text.txt", "r");
while ((ch = fgetc(fp)) != EOF)
{
for (i = 0; i < 6; ++i)
{
if (ch == operators[i])
{
printf(" OPERATOR: %c \n", ch);
}
else if (ch == separators[i])
printf(" SEPARATOR: %c \n", ch);
}
if (isalnum(ch))
{
buffer[j++] = ch;
}
else if ((ch == ' ' || ch == '\n') && (j != 0))
{
buffer[j] = '\0';
j = 0;
{
if (isKeyword(buffer) == 1)
printf(" KEYWORD: %s \n", buffer);
else
printf(" IDENTIFIER: %s \n", buffer);
}
}
}
fclose(fp);
return 0;
}

replacing integers with strings in C

I wrote code that replaces integers from 0 to 3 with strings. I was only allowed to use getchar() and putchar(). If the input is 1, the output will become "one".
#include <stdio.h>
int main()
{
int c;
char* arr[4] = {"zero", "one", "two","three"};
int i;
while ((c = getchar ()) != EOF)
{
if(c==0+'0') {
char* str = arr[0];
for (i = 0; str[i] != '\0'; i++) {
putchar(str[i]);
}
}
else if(c==1+'0') {
char* str = arr[1];
for (i= 0; str[i] != '\0';i++) {
putchar(str[i]);
}
}
else if(c==2+'0') {
char* str = arr[2];
for (i = 0; str[i] != '\0'; i++) {
putchar(str[i]);
}
}
else if(c==3+'0') {
char* str = arr[3];
for (i = 0; str[i] != '\0'; i++) {
putchar(str[i]);
}
}
else
putchar(c);
}
return 0;
}
The code is pretty long. Is there a shorter way to write it?
If I type in 33 the output will be "threethree". Could anyone give me suggestions how can i modify my code not to do that?
note: I am also not allowed to use functions.
You can use a variable to remember last input and compare, so that you will not print continuous char.
#include <stdio.h>
int main()
{
int c;
char* arr[4] = {"zero", "one", "two","three"};
int i;
char last_input = '9';
while ((c = getchar ()) != EOF)
{
if(c != last_input && '0' <= c && c <= '3') {
last_input = c;
int index = c - '0';
char* str = arr[index];
for (i = 0; str[i] != '\0'; i++) {
putchar(str[i]);
}
}
else{
putchar(c);
}
}
return 0;
}
You can compress your if statements using one if condition like this :
#include <stdio.h>
int main()
{
int c;
char* arr[4] = {"zero", "one", "two","three"};
int i;
while ((c = getchar ()) != EOF) {
int k = c-'0';
if(k>=0 && k<=3) {
char* str = arr[k];
for (i= 0; str[i] != '\0';i++) {
putchar(str[i]);
}
}
else {
putchar(c);
}
}
return 0;
}
Here is the simple approach to the same task. I tried to explain the logic in the comments.
int main(void) {
char *arr[11] = {"zero", "one", "two","three","four","five","six","seven","eight","Nine","Ten"};
int *input = malloc(sizeof(*input))/*1st time 4 byte */ , row = 1;
while( (input[row-1] = getchar())!=EOF ) {
if(input[row-1]==10) /* if ENTER key is presed */
break;
input[row-1] = input[row-1] - 48;/* convert it */
printf("%s ",arr[ input[row-1]%10 ]);/* its simple, just think on it */
row++;
input = realloc(input,row * sizeof(*input));/* reallocate based on number of input */
}
/* free dynamically allocated memory #TODO*/
return 0;
}
I just given hint, make it generic like write the condition if input is less than zero etc. I hope it helps.
Here my code using loop to shorten your code.
#include <stdio.h>
int main()
{
int c;
char* arr[4] = {"zero", "one", "two","three"};
int i, j;
while ((c = getchar ()) != EOF)
{
for(j = 0; j < 4; j++)
{
if(c == j + '0')
{
char* str = arr[j];
for (i = 0; str[i] != '\0'; i++)
{
putchar(str[i]);
}
j = 10; // just to detect processed character
break;
}
}
if(j != 10)
{
putchar(c);
}
}
return 0;
}

C - Can't add to or call specific array?

My program takes two parameters eg "./a abc xyz" where all a's in a text file are replaced with x's and b's with y's and so on. When given a range, eg. A-C, it reads it as ABC.
The issue I am having is that when I add chars to a certain array(alphaRange2) I get a segmentation fault when I run it. I use the same code for array alphaRange1, which does accept the chars as shown when I print alphaRange1 in a for loop. When I try to print alphaRange2, no values are printed.
Here's my code:
int translate(char set1[], char set2[]) {
int c;
char ch;
char ch2;
int dash1 = 0;
int dash2 = 0;
int previous = -1;
int next;
char alphaRange1[MAXSIZE];
char alphaRange2[MAXSIZE];
size_t i;
int j = 0;
int k;
int l;
for (i=0; i <= strlen(set1); i++) {
if (set1[i] == '-') {
for (ch = set1[i-1]; ch <= set1[i+1]; ch++) {
alphaRange1[k] = ch;
k++;
}
}
}
for (i=0; i <= strlen(set2); i++) {
if (set2[i] == '-') {
for (ch = set2[i-1]; ch <= set2[i+1]; ch++) {
alphaRange2[l] = ch;
l++;
}
}
}
/*for (i=0; alphaRange1[i] != '\0'; i++) {
printf("%c", alphaRange1[i]);
}*/
while ((c = getchar()) != EOF) {
if ((dash1 == 1) && (dash2 == 1)) {
for (i=0; alphaRange1[i] != '\0' || alphaRange2[i] != '\0'; i++) {
if (c == alphaRange1[i]) {
c = alphaRange2[i];
}
}
} else if ((dash1 == 0) && (dash2 == 0)) {
for (i=0; i <= strlen(set1) || i <= strlen(set2); i++) {
if (c == set1[i]) {
c = set2[i];
if ((c == set1[1]) && (set1[1] == set2[0])) {
c = set2[0];
break;
}
}
}
}
if (previous > -1) {
putchar(previous);
}
previous = c;
}
putchar('\n');
return 1;
}
int main(int argc, char *argv[]) {
int i, j, k;
char set1[MAXSIZE];
char set2[MAXSIZE];
char ch;
char alphaRange1[MAXSIZE];
for (i=0; i < argc; i++) {
for (j=0; argv[1][j] != '\0' || argv[2][j] != '\0'; j++) {
set1[i] = argv[1][i];
set2[i] = argv[2][i];
}
}
/*for (i=0; i <= strlen(set1); i++) {
if (set1[i] == '-') {
for (ch = set1[i-1]; ch <= set1[i+1]; ch++) {
alphaRange1[k] = ch;
k++;
}
}
}
for (i=0; alphaRange1[i] != '\0'; i++) {
printf("%c", alphaRange1[i]);
}*/
translate(set1, set2);
return 1;
}
The code runs if you take out anything including alphaRange2, and I've been testing it using commented out print loop, which works if you comment out the entire while loop. How do I make this work?
Thanks.

Resources