I had this school project that I'm working on. I am done, I just need to edit it a bit and am running into a issue. I sent my code to my professor so he could check it over and there's only one thing wrong with it.
All your array notations need to change to pure pointer notations such as *s1 or s1++, etc. nothing like *(random + 41 - 1) or *(s2_input + count) - you need to update your pointer and use dereference (exactly what you are doing in strfilter function.
He wouldn't explain further, so I am just confused on how exactly I would change my code. I have figured out my code is still in a array notation in a couple spots but any help would be appreciated.
Such as *(random + 41 - 1) = '\0'; , *(s2_input + count) = '\0'; , and *(s2_input + count) = input;. What can I do to fix this?
#include <stdio.h>
#include <stdlib.h>
/*Function Prototypes*/
int main();
void s1(char *random);
void s2(char *s2_input, int index);
void strfilter(char *random, char *s2_input, char replacement);
int main()
{
for(;;)
{
int s1_index = 41;
char s1_random[s1_index];
s1(s1_random);
printf("\ns1 = ");
puts(s1_random);
printf("s2 = ");
int s2_index = 21;
char s2_input[s2_index];
s2(s2_input, s2_index);
if(s2_input[1] == '\0')
{
printf("Size too small");
exit(0);
}
if(s2_input[21] != '\0' )
{
printf("Size too big");
exit(0);
}
printf("ch = ");
int replacement = getchar();
if(replacement == EOF)
break;
while(getchar() != '\n');
printf("\n");
strfilter(s1_random, s2_input, replacement);
printf("\ns1 filtered = ");
puts(s1_random);
printf("Do you wish to run again? Yes(Y), No(N) ");
int run = getchar();
// or include ctype.h and do:
// run == EOF || toupper(run) == 'N'
if(run == EOF || run == 'N' || run == 'n')
break;
while(getchar() != '\n');
}
}
void s1(char *random)
{
int limit = 0;
char characters;
while((characters = (('A' + (rand() % 26))))) /* random generatro */
{
if(limit == 41)
{
*(random + 41 - 1) = '\0';
break;
}
*(random + limit) = characters;
limit++;
}
}
void s2(char *s2_input, int index)
{
char array[21] = "123456789012345678901"; /* populated array to make sure no random memory is made */
char input;
int count = 0;
int check = 0;
while((input = getchar() ))
{
if(input == '\n')
{
*(s2_input + count) = '\0';
break;
}
else if(input < 65 || input > 90)
{
printf("invalid input");
exit(0);
}
*(s2_input + count) = input;
count++;
}
index = count;
}
void strfilter(char *random, char *s2_input, char replacement) /* replacement function */
{
while(*s2_input)
{
char *temp = random;
while(*temp)
{
if(*temp == *s2_input)
*temp = replacement;
temp++;
}
s2_input++;
}
}
I tried a making a temporary pointer and replacing it with the array notation but I still would need to have the array notation somewhere. I can have the array defined somewhere but that's it. Any help would be greatly appreciated!
I just got clarification from the professor on what he wants.
You don't have to initialize s2 as an array you can initialize it as pointer to integer (int s2;) then you can do a pointer to an array (int (s1)[41];) then point to the single element of the array by doing this: s2 = s1; and incriminating to the next element by doing this: s2++
Does this make sense to anyone? I understand that he wants me to make a int pointer, and then use that to point to a certain element in the array however I am not sure on how to implement that.
I interpreted this as that you need to replace
*(random + limit) = characters;
with
*random++=characters;
and
*(s2_input + count) = input;
becomes
*s2_input++ = input;
i.e. he is asking you to move the pointer to the next point as you use it rather than recalculate each time.
Below are 3 ways of doing the same thing.
void s1(char *random)
{
for(int limit=0;limit<40;++limit)
{
char characters = 'A' + (rand() % 26);
// random[limit]=characters;
// *(random + limit) = characters;
*random++=characters;
}
// random[limit]='\0';
// *(random + limit) = '\0';
*random='\0';
}
A few issues ...
Hardwiring the limit in s1 is bad. Better to pass the max length as an arg.
The "Size too big" check in main must be done in s2 to prevent overflow/UB.
Here is the refactored code. I just fixed the pointer usage, but didn't test otherwise.
#include <stdio.h>
#include <stdlib.h>
/*Function Prototypes*/
int main();
#if 0
void s1(char *random);
#else
void s1(char *random,int maxlen);
#endif
#if 0
void s2(char *s2_input, int index);
#else
int s2(char *s2_input, int index);
#endif
void strfilter(char *random, char *s2_input, char replacement);
int
main()
{
for (;;) {
int s1_index = 41;
char s1_random[s1_index];
s1(s1_random,s1_index);
printf("\ns1 = ");
puts(s1_random);
printf("s2 = ");
int s2_index = 21;
char s2_input[s2_index];
#if 0
s2(s2_input, s2_index);
if (s2_input[1] == '\0') {
printf("Size too small");
exit(0);
}
#else
int len = s2(s2_input, s2_index);
if (len < 2) {
printf("Size too small\n");
exit(0);
}
#endif
// NOTE/BUG: the s2 function has to check this -- if too much data entered,
// s2 will overflow the buffer before we get here (causing UB)
#if 0
if (s2_input[21] != '\0') {
printf("Size too big");
exit(0);
}
#endif
printf("ch = ");
int replacement = getchar();
if (replacement == EOF)
break;
while (getchar() != '\n');
printf("\n");
strfilter(s1_random, s2_input, replacement);
printf("\ns1 filtered = ");
puts(s1_random);
printf("Do you wish to run again? Yes(Y), No(N) ");
int run = getchar();
// or include ctype.h and do:
// run == EOF || toupper(run) == 'N'
if (run == EOF || run == 'N' || run == 'n')
break;
while (getchar() != '\n');
}
}
void
s1(char *random,int maxlen)
{
#if 0
int limit = 0;
char characters;
/* random generatro */
while ((characters = (('A' + (rand() % 26))))) {
if (limit == 41) {
*(random + 41 - 1) = '\0';
break;
}
*(random + limit) = characters;
limit++;
}
#else
char characters;
/* random generatro */
for (--maxlen; maxlen > 0; --maxlen) {
characters = 'A' + (rand() % 26);
*random++ = characters;
}
*random = 0;
#endif
}
#if 0
void
s2(char *s2_input, int maxlen)
{
/* populated array to make sure no random memory is made */
char array[21] = "123456789012345678901";
char input;
int count = 0;
int check = 0;
while ((input = getchar())) {
if (input == '\n') {
*(s2_input + count) = '\0';
break;
}
else if (input < 65 || input > 90) {
printf("invalid input");
exit(1);
}
*(s2_input + count) = input;
count++;
}
index = count;
}
#else
int
s2(char *s2_input, int maxlen)
{
int input;
int count = 0;
--maxlen;
while ((input = getchar()) != EOF) {
if (input == '\n')
break;
if (input < 65 || input > 90) {
printf("invalid input\n");
exit(0);
}
if (maxlen <= 0) {
printf("input too long\n");
exit(1);
}
*s2_input++ = input;
--maxlen;
++count;
}
*s2_input = 0;
return count;
}
#endif
/* replacement function */
void
strfilter(char *random, char *s2_input, char replacement)
{
while (*s2_input) {
char *temp = random;
while (*temp) {
if (*temp == *s2_input)
*temp = replacement;
temp++;
}
s2_input++;
}
}
In the above code, I've used cpp conditionals to denote old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note: this can be cleaned up by running the file through unifdef -k
Related
I tried to make calculator supporting brackets, but
I have no idea how to deal if the user's input includes expression with spaces, for example:
input: (2 + 3) * 2
i got: 2
If it's normally get (2+3)*2, it counts 10
.
My code:
#include <stdio.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
scanf("%s", str);
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
`
str ++; /* point to the next character of the expression */
}
`
printf("%d\n",operand[0]); /*output result*/
return 0;
I tried to count the equation even if there is a space in it. Can someone please help?
Solving the problem by removing spaces:
So if you're working with equation as string you can simply remove spaces with function like this (there will be probably better way or function in library string.h but this was first guess):
char* DeleteSpaces( char* stringWithSpaces, size_t lengthOfString)
{
char* stringWithoutSpaces = (char*)calloc(lengthOfString + 1, sizeof(char));
if( !stringWithoutSpaces )
return NULL;
for( unsigned int x = 0, y = 0; x <= lengthOfString; x++, y++ )
{
if( stringWithSpaces[x] == ' ' ) // if the character is space
{
while( stringWithSpaces[x] == ' ' && x < lengthOfString ) // skip all the spaces OR go away before you hit '\0'
x++;
stringWithoutSpaces[y] = stringWithSpaces[x]; // then copy next character into new string
}
else // if there's no space just copy the character
stringWithoutSpaces[y] = stringWithSpaces[x];
}
return stringWithoutSpaces;
}
This will basically remove all spaces from your received equation. If you really need the smallest possible memory requirement you can use realloc() at the end of the function for more optimal memory usage.
Here's simple example of how to use the function so you can test it:
int main()
{
char firstString[] = "H e l l o w o r l d\0";
char* secondString;
secondString = DeleteSpaces( firstString, strlen(firstString) );
if( !secondString )
return -1;
printf( "%s", secondString );
free( secondString );
return 0;
}
Don't forget to use free(SecondString). I hope I helped you atleast a little :)
As with the previous answer, I added in a function to remove any spaces from the entered formula in order to process the requested calculation. Also, coupled with that, I revised the "scanf" input to read in all of the entered characters which looked to be another symptom you were facing. With that, following is a refactored version of your program with the additional space compression function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_SIZE 1024
int insert_operand(int *operand, int * top_num, int num) /* data is pushed into the data stack*/
{
(*top_num) ++;
operand[*top_num] = num; /*save data*/
return 0; /*Exit normally*/
}
int insert_oper (char * oper , int *top_oper , char ch)
{
(*top_oper)++;
oper[*top_oper] = ch; /*save operator*/
return 0; /*Exit normally*/
}
int compare(char *oper , int *top_oper , char ch) /* compare the priority of the operating server*/
{
if((oper[*top_oper] == '-' || oper[*top_oper] == '+') /*Determine whether the current priority is higher than the priority of the operator at the top of the stack*/
&& (ch == '*' || ch == '/'))
{
return 0;
}
else if(*top_oper == -1 || ch == '('
|| (oper[*top_oper] == '(' && ch != ')')) /*Determine whether the operator stack is empty; whether the top operator is '('*/
{
return 0;
}
else if (oper[*top_oper] =='(' && ch == ')')
{
(*top_oper)--;
return 1;
}
else
{
return -1; /*Operate the operator*/
}
}
int deal_date(int *operand ,char *oper ,int *top_num, int *top_oper) /*perform data operation*/
{
int num_1 = operand[*top_num]; /*Take out two data from the data stack*/
int num_2 = operand[*top_num - 1];
int value = 0;
if(oper[*top_oper] == '+')
{
value = num_1 + num_2;
}
else if(oper[*top_oper] == '-')
{
value = num_2 - num_1;
}
else if(oper[*top_oper] == '*')
{
value = num_2 * num_1;
}
else if(oper[*top_oper] == '/')
{
value = num_2 / num_1;
}
(*top_num) --; /*Move the top of the data stack down one bit*/
operand[*top_num] = value; /*Push the obtained value into the data stack*/
(*top_oper) --; /*Move the top of the operator stack down one bit*/
return value;
}
void compress(char *stx) /* The additional function */
{
char work[101];
int i = strlen(stx);
strcpy(work, stx);
for (int j = 0; j < i; j++)
{
stx[j] = 0;
}
i = 0;
for (int j = 0; j < (int)strlen(work); j++)
{
if (work[j] != ' ')
{
stx[i] = work[j];
i++;
}
}
}
int main()
{
int operand[MAX_SIZE] = {0}; /*data stack, initialize*/
int top_num = -1;
char oper[MAX_SIZE] = {0}; /*operator stack, initialize*/
int top_oper = -1;
char *str = (char *) malloc (sizeof(char) * 100); /*get expression (without =)*/
//scanf("%s", str);
scanf("%[^\n]", str); /* Refined the scanf call to receive all characters prior to the newline/return character */
compress(str); /* Added this function to remove spaces */
char* temp;
char dest[MAX_SIZE];
int num = 0;
int i = 0;
while(*str != '\0')
{
temp = dest;
while(*str >= '0' && *str <= '9') /*judging whether it is data*/
{
*temp = *str;
str++;
temp++;
} /*Encounter a symbol to exit*/
if(*str != '(' && *(temp - 1) != '\0') /*Determine whether the symbol is '('*/
{
*temp = '\0';
num = atoi(dest); /*convert string to number*/
insert_operand(operand, &top_num,num); /*Push data into the data stack*/
}
while(1)
{
i = compare(oper,&top_oper,*str); /*judgment operator priority*/
if(i == 0)
{
insert_oper(oper,&top_oper,*str); /*press operator*/
break;
}
else if(i == 1) /*judging whether the expression in brackets ends*/
{
str++;
}
else if(i == -1) /* data processing */
{
deal_date(operand,oper,&top_num,&top_oper);
}
}
str ++; /* point to the next character of the expression */
}
printf("%d\n",operand[0]); /*output result*/
return 0;
}
Testing out your sample formula with some additional spacing to ensure the compression function was working properly, following was the terminal output.
#Vera:~/C_Programs/Console/Calculate/bin/Release$ ./Calculate
(2 + 3) * 2
10
Give that a try and see if it meets the spirit of your project.
As pointed out in the comments and other answers, the solution may be to simply "compact" the spaces out of the string before trying to analyse the string's content.
This doesn't require a lot of code:
#include <stdio.h>
char *stripSP( char *src ) {
for( char *d = src, *s = src; ( *d = *s ) != '\0'; s++ )
d += *d != ' ';
return src;
}
int main( void ) {
char *s[] = { "Hello", "H e l l ooo", "(2 + 5) * 3" };
for( int i = 0; i < 3; i++ ) {
printf( "From '%s' ", s[i] );
printf( "'%s'\n", stripSP( s[i] ) );
}
return 0;
}
From 'Hello' 'Hello'
From 'H e l l ooo' 'Hellooo'
From '(2 + 5) * 3' '(2+5)*3'
Even more compact would be to use array indexing:
char *stripSP( char s[] ) {
for( int f=0, t=0; (s[t] = s[f++]) != '\0'; t += s[t] != ' ' ) {}
return s;
}
I have this coding assignment where I have to use pure pointer notation only. I am pretty much finished with it but I just realized that I used an array. I am not allowed to do so, unless I change it into a pointer somehow. That's where I am slightly stuck.
This is my code.
#include <stdio.h>
#include <stdlib.h>
/* Function Prototypes */
int main();
void s1(char *random);
void s2(char *s2_input, int index);
void strfilter(char *random, char *s2_input, char replacement);
int main()
{
for(;;)
{
int s1_index = 41;
char s1_random[s1_index];
s1(s1_random);
printf("\ns1 = ");
puts(s1_random);
printf("s2 = ");
int s2_index = 21;
char s2_input[s2_index];
s2(s2_input, s2_index);
if(s2_input[1] == '\0')
{
printf("Size too small");
exit(0);
}
if(s2_input[21] != '\0' )
{
printf("Size too big");
exit(0);
}
printf("ch = ");
int replacement = getchar();
if(replacement == EOF)
break;
while(getchar() != '\n');
printf("\n");
strfilter(s1_random, s2_input, replacement);
printf("\ns1 filtered = ");
puts(s1_random);
printf("Do you wish to run again? Yes(Y), No(N) ");
int run = getchar();
// or include ctype.h and do:
// run == EOF || toupper(run) == 'N'
if(run == EOF || run == 'N' || run == 'n')
break;
while(getchar() != '\n');
}
}
void s1(char *random)
{
int limit = 0;
char characters;
while((characters = (('A' + (rand() % 26))))) /* random generator */
{
if(limit == 41)
{
*(random + 41 - 1) = '\0';
break;
}
*(random + limit) = characters;
limit++;
}
}
void s2(char *s2_input, int index)
{
char array[21] = "123456789012345678901"; /* populated array to make sure no random memory is made */
char input;
int count = 0;
int check = 0;
while((input = getchar() ))
{
if(input == '\n')
{
*(s2_input + count) = '\0';
break;
}
else if(input < 65 || input > 90)
{
printf("invalid input");
exit(0);
}
*(s2_input + count) = input;
count++;
}
index = count;
}
void strfilter(char *random, char *s2_input, char replacement) /* replacement function */
{
while(*s2_input)
{
char *temp = random;
while(*temp)
{
if(*temp == *s2_input)
*temp = replacement;
temp++;
}
s2_input++;
}
}
My issue is this part I am not sure how to edit this to not include an array, and still have it output the program in the same way.
if(s2_input[1] == '\0')
{
printf("Size too small");
exit(0);
}
if(s2_input[21] != '\0' )
{
printf("Size too big");
exit(0);
}
I tried to take the address of the array at a certain point, and then dereference it with a pointer, however that is still using a array. Which is what I am trying to avoid. Any help would be greatly appreciated!
s2_input[i] can be written as *(s2_input+i) where i is some index.
if ((s2_input[1]) == '\0')
is equivalent to:
if (*(s2 + 1) == '\0')
Which means to dereference the value at s2 (which is the location of the zeroth[0] element), and add one to it.
The same could be done for any other location.
Pointer notation and what is often referred to as Indexed notation (which uses the [ ] subscript operator) are entirely equivalent. Either notion provides the pointer address plus an offset from that pointer address. See C11 Standard - 6.5.2.1 Array subscripting That being array[offset] or *(array + offset)1
For example accessing the first element using *array is shorthand for *(array + 0) which is simply array[0] in indexed notation. The 0 being the offset (in elements of that type) from the original pointer address. (type controls pointer arithmetic)
So array[10] is simply *(array + 10). If array is type char, array[10] is 10-bytes after array address. If array is type int (where an int is 4-bytes), then array[10] is 40-bytes after array address (10-int).
For a 2D array, the notation for arr2d[1][2] would simply be *(arr2d[1] + 2) which expanded further is simply *(*(arr2d + 1) + 2).
So generally array[i] is *(array + i) and arr2d[i][j] is *(*(arr2d + i) + j).
footnotes:
It follows that array[offset] is equivalent to *(array + offset) is equivalent to offset[array].
I'm stuck on an assignment I have to read from console really long number and then print it out using char* arr. Then I need to add and subtract number 1 array to number2 array. To be honest adding and subtracting I will probably deal on my own but I cannot figure out how to read those input characters, character by character and make while break after enter in console.
My code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int subtract(const char* number1, const char* number2, char** result){
if(number1 == NULL || number2 == NULL){
return 1;
}
return 0;
}
int add(const char* number1, const char* number2, char** result) {
if(number1 == NULL || number2 == NULL){
return 1;
}
return 0;
}
int input_check(int check, char* number) {
if (check != 1) {
return 1;
}
else {
return 0;
}
}
int main()
{
char* number1;
//char* number2;
//char** result;
int check = 0;
number1 = (char*)calloc(200,sizeof(char));
//number2 = (char*)calloc(200, sizeof(char));
//result = (char*)malloc(sizeof(char) * sizeof(char) * 400);
if (number1 == NULL) {
printf("Failed to allocate memory");
return 8;
}
printf("Input first num: ");
int i = 0;
while (1) {
char retVal;
scanf("%c", &retVal);
if (retVal >= 48 || retVal <= 57 || retVal != '\0') {
*(number1 + i) = retVal;
if ((number1 + i) == NULL) {
break;
}
printf("%d", atoi((number1 + i)));
i++;
}
else
{
break;
}
}
return 0;
}
Thanks for any help
As there is no limit on the numbers, you need to use dynamic memory allocation.
The straightforward (brute-force) way is to keep increasing the allocated size
char *input = calloc(1, 1); // space for '\0'
size_t len = 0;
for (;;) {
int ch = getchar();
if (ch != '\n') {
input[len] = ch; // replace '\0' with ch
len++;
char *tmp = realloc(input, len + 1);
if (tmp == NULL) exit(EXIT_FAILURE);
input = tmp;
input[len] = 0; // add '\0'
} else {
break;
}
}
// use input and len
free(input);
Here is my problem:
The Caesar Cipher technique is one of the earliest and simplest methods of encryption technique. It’s simply a type of substitution cipher, i.e., each letter of a given text is replaced by a letter some fixed number of positions down the alphabet. For example with a shift of 1, A would be replaced by B, B would become C, and so on. The method is apparently named after Julius Caesar, who apparently used it to communicate with his officials.
Thus to cipher a given text we need an integer value, known as a shift which indicates the number of position each letter of the text has been moved down.
The encryption can be represented using modular arithmetic by first transforming the letters into numbers, according to the scheme, A = 0, B = 1,…, Z = 25. Encryption of a letter by a shift n can be described mathematically as.
E_n(x)=(x+n)mod\ 26
(Encryption Phase with shift n)
D_n(x)=(x-n)mod\ 26
(Decryption Phase with shift n)
Write an algorithm and implement a program in c to read the data from a file(called "test.txt"), transform the data according to the discussion in and aftwerward save it in another file(called "final.txt")
Here is my code but I can't find out what to do
#include <stdio.h>
#include <stdlib.h>
char data[50], temp; int key, count;
void
getmessage()
{
// printf("Enter a String:\t");
// scanf("%[^\n]s", data);
FILE *file_pointer;
char buffer[30], c;
file_pointer = fopen("test.txt", "r");
printf("----reading the file----\n");
fgets(buffer, 50, file_pointer);
data[50] = buffer;
printf("%s\n", buffer);
#if 0
printf("----read and parse data----\n");
file_pointer = fopen("test.txt", "r"); // reset the pointer
char str1[10], str2[2], str3[20], str4[2];
fscanf(file_pointer, "%s %s %s %s", str1, str2, str3, str4);
printf("Read String1 |%s|\n", str1);
printf("Read String2 |%s|\n", str2);
printf("Read String3 |%s|\n", str3);
printf("Read String4 |%s|\n", str4);
#endif
}
void
key_input()
{
printf("Enter a Key:\t");
scanf("%d", &key);
}
void
caesar_cipher_encryption()
{
for (count = 0; data[count] != '\0'; count++) {
temp = data[count];
if (temp >= 'a' && temp <= 'z') {
temp = temp + key;
if (temp > 'z') {
temp = temp - 'z' + 'a' - 1;
}
data[count] = temp;
}
else if (temp >= 'A' && temp <= 'Z') {
temp = temp + key;
if (temp > 'Z') {
temp = temp - 'Z' + 'A' - 1;
}
data[count] = temp;
}
}
printf("\nEncrypted Message:\t%s\n", data);
}
void
caesar_cipher_decryption()
{
for (count = 0; data[count] != '\0'; count++) {
temp = data[count];
if (temp >= 'a' && temp <= 'z') {
temp = temp - key;
if (temp < 'a') {
temp = temp + 'z' - 'a' + 1;
}
data[count] = temp;
}
else if (temp >= 'A' && temp <= 'Z') {
temp = temp - key;
if (temp < 'A') {
temp = temp + 'Z' - 'A' + 1;
}
data[count] = temp;
}
}
printf("\nDecrypted Message:\t%s\n", data);
}
int
main()
{
int choice;
getmessage();
key_input();
while (1) {
printf("\n1. Encryption\n2. Decryption\n3. Exit\n");
printf("\nEnter You Choice:\t");
scanf("%d", &choice);
switch (choice) {
case 1:
caesar_cipher_encryption();
break;
case 2:
caesar_cipher_decryption();
break;
case 3:
exit(0);
default:
printf("\nPlease select a correct option:\n");
}
}
printf("\n");
return 0;
}
Your input of the data string in get_message is wrong:
It has UB (undefined behavior) because it writes past the end of buffer.
Also, buffer is never copied to [the global variable] data, so data always has garbage.
Better to input directly to data [and eliminate buffer]. This seems okay because the other functions use the global data
We should increase the size of the buffers to allow for longer phrases
Both the encryption and decryption functions replicate the code depending upon whether the character is upper or lower case. We should create two functions to centralize the transformations (passing limits as arguments).
The actual encryption/description algorithms don't match [AFAICT during testing].
Here's some refactored code. It is annotated and I've used cpp conditionals to show old vs. new code:
#if 0
// old code
#else
// new code
#endif
#if 1
// new code
#endif
Note that this code could be further cleaned up but I didn't want to get further afield of the existing code (e.g. change functions to accept buffer pointers as parameters, etc.):
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// NOTE/BUG: data must be [at least] the same size as buffer in getmessage
// NOTE/BUG: temp should be function scoped
#if 0
char data[50], temp;
#else
#define BUFMAX 1000
char data[BUFMAX];
#endif
int key, count;
void
getmessage()
{
// printf("Enter a String:\t");
// scanf("%[^\n]s", data);
FILE *file_pointer;
// NOTE/BUG: the buffer is local and we can input directly into temp
#if 0
char buffer[30], c;
#endif
// NOTE/BUG: there is no corresponding fclose for this
file_pointer = fopen("test.txt", "r");
printf("----reading the file----\n");
// NOTE/BUG: this causes UB (undefined behavior) because we store past the
// end of buffer
// NOTE/BUG: buffer never gets into data
// NOTE/BUG: newline is not stripped properly
#if 0
fgets(buffer, 50, file_pointer);
data[50] = buffer;
printf("%s\n", buffer);
// NOTE/FIX: we can input directly into data
#else
if (file_pointer == NULL) {
perror("test.txt");
exit(1);
}
fgets(data, sizeof(data), file_pointer);
data[strcspn(data,"\n")] = 0;
fclose(file_pointer);
printf("%s\n", data);
#endif
#if 0
printf("----read and parse data----\n");
file_pointer = fopen("test.txt", "r"); // reset the pointer
char str1[10], str2[2], str3[20], str4[2];
fscanf(file_pointer, "%s %s %s %s", str1, str2, str3, str4);
printf("Read String1 |%s|\n", str1);
printf("Read String2 |%s|\n", str2);
printf("Read String3 |%s|\n", str3);
printf("Read String4 |%s|\n", str4);
#endif
}
void
key_input()
{
printf("Enter a Key:\t");
scanf("%d", &key);
}
int
encrypt(int chr,int lo,int hi)
{
if ((chr >= lo) && (chr <= hi)) {
chr += key;
if (chr > hi) {
chr -= hi;
chr += lo;
chr -= 1;
}
}
else
chr = 0;
return chr;
}
int
decrypt(int chr,int lo,int hi)
{
if ((chr >= lo) && (chr <= hi)) {
chr -= key;
if (chr < lo) {
chr = chr - lo;
chr += hi;
chr += 1;
}
}
else
chr = 0;
return chr;
}
void
caesar_cipher_encryption()
{
int temp;
int code;
for (count = 0; data[count] != '\0'; count++) {
temp = data[count];
code = encrypt(temp,'a','z');
if (code) {
data[count] = code;
continue;
}
code = encrypt(temp,'A','Z');
if (code) {
data[count] = code;
continue;
}
}
printf("\nEncrypted Message:\t%s\n", data);
}
void
caesar_cipher_decryption()
{
int temp;
int code;
for (count = 0; data[count] != '\0'; count++) {
temp = data[count];
code = decrypt(temp,'a','z');
if (code) {
data[count] = code;
continue;
}
code = decrypt(temp,'A','Z');
if (code) {
data[count] = code;
continue;
}
}
printf("\nDecrypted Message:\t%s\n", data);
}
int
main()
{
int choice;
getmessage();
key_input();
while (1) {
printf("\n1. Encryption\n2. Decryption\n3. Exit\n");
printf("\nEnter You Choice:\t");
scanf("%d", &choice);
switch (choice) {
case 1:
caesar_cipher_encryption();
break;
case 2:
caesar_cipher_decryption();
break;
case 3:
exit(0);
default:
printf("\nPlease select a correct option:\n");
}
}
printf("\n");
return 0;
}
I have a program where my code uses a goto statement, and I want to get rid of it in a nice way, but I can't seem to find a solution. If goto is the best way, then please let me know. Here is a summary of the code:
//Counts how many times every word appears in a file
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NUMWORDS 1000
#define WORDLEN 50
typedef struct
{
char word[WORDLEN + 1];
int num;
} Appearance;
int main(int argc, char *argv[]) {
FILE *readfile;
Appearance *appearlist[NUMWORDS] = {NULL};
char word[WORDLEN + 1];
int i;
//Get a valid filename and open the file, store pointer into readfile
...
char c;
while (c != EOF) {
skip: //Annoying label
//Get a word from readfile, store into word
...
if (word[0] != '\0') {
for (i = 0; i < NUMWORDS && appearlist[i]; i++) {
if (strcmp(appearlist[i] -> word, word) == 0) {
appearlist[i] -> num++;
goto skip; //Annoying goto
}
}
appearlist[i] = (Appearance *) malloc(sizeof(Appearance));
appearlist[i] -> num = 1;
strcpy(appearlist[i] -> word, word);
}
}
//Display results, free memory
...
return 0;
}
The problem is, I want to skip code that is outside of the loop I want to skip from. I would like to not create another variable only designed for this. If you want the full code, click on "Show code snippet."
//Counts how many times every word appears in a file
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define NUMWORDS 1000
#define WORDLEN 50
#define FILENAMELEN 50
typedef struct
{
char word[WORDLEN + 1];
int num;
} Appearance;
int main(int argc, char *argv[])
{
char filename[FILENAMELEN];
FILE *readfile;
Appearance *appearlist[NUMWORDS] = {NULL};
char word[WORDLEN + 1];
size_t ln;
int i;
if (argc == 2)
strncpy(filename, argv[1], sizeof(filename));
else {
printf("Enter a filename to count appearances from, or just press enter to quit: ");
fgets(filename, FILENAMELEN, stdin);
ln = strlen(filename) - 1;
if (filename[ln] == '\n')
filename[ln] = '\0';
}
while((readfile = fopen(filename, "r")) == NULL) {
if (filename[0] == '\0')
return 0;
printf("Invalid file! Please enter another filename, or just press enter to quit: ");
fgets(filename, FILENAMELEN, stdin);
ln = strlen(filename) - 1;
if (filename[ln] == '\n') filename[ln] = '\0';
}
char c;
while (c != EOF) {
skip:
for (i = 0; (c = getc(readfile)) != EOF && (isalnum(c) || c == '\''); i++) {
if (i >= WORDLEN) {
word[i] = '\0';
printf("\nWarning: word too long (over %d characters), trimming to: %s\n", WORDLEN, word);
while ((c = getc(readfile)) != EOF && (isalnum(c) || c == '\'')) ;
} else {
word[i] = tolower(c);
}
}
word[i] = '\0';
if (word[0] != '\0') {
for (i = 0; i < NUMWORDS && appearlist[i]; i++) {
if (strcmp(appearlist[i] -> word, word) == 0) {
appearlist[i] -> num++;
goto skip;
}
}
appearlist[i] = (Appearance *) malloc(sizeof(Appearance));
appearlist[i] -> num = 1;
strcpy(appearlist[i] -> word, word);
}
}
for (i = 0; i < NUMWORDS && appearlist[i]; i++) {
printf("Word: %s, Appearances: %d\n", appearlist[i] -> word, appearlist[i] -> num);
free(appearlist[i]);
}
return 0;
}
Using goto in this case is often considered acceptable.
Alternatives would be to set a variable so that you can continue in the outer loop after breaking from the inner one, or turning the whole segment that you want to escape from into a separate function, and returning from it instead of using goto.
I'm ignoring any other issues there may be with the code that aren't relevant to the question!
Put everything beginning with the 'if' statement into a separate method (let's call it "process" and replace the goto with return. Then the while-loop becomes:
while (c != EOF) {
//Get a word from readfile, store into word
...
process(...);
}
Sometimes using goto is a hint that code should use a helper function
static bool findword(Appearance *appearlist, size_t size, const char *word) {
for (size_t i = 0; i < size && appearlist[i]; i++) {
if (strcmp(appearlist[i]->word, word) == 0) {
appearlist[i]->num++;
return true;
}
}
return false;
}
while (c != EOF) {
//Get a word from readfile, store into word
...
if (word[0] != '\0') {
if (findword(appearlist, NUMWORDS, word)) {
continue;
}
appearlist[i] = (Appearance *) malloc(sizeof(Appearance));
appearlist[i] -> num = 1;
strcpy(appearlist[i] -> word, word);
}
}