Comparing elements in a 2D array - c

I'm trying to compare elements being fed in from a text file into my 2D array. An example of the textfile is as follows:
ABCDE
FGHIK
LMNOP
I know I can read in the file fine and can print each element as well.
I'm trying to go through and compare each character with the next. In my head this is how it works:
If they match, move on to the next char, then compare that char with the next. If they do not match, then print "error" to the terminal and break out of the switch statement. Though when I run this in my program it only prints "Is this being accsessed?" "It sure is". Any help on what I could be doing wrong would be very helpful.
void match_char(char** array, int height, int width){
int a, i, j;
printf("Is this being accessed?");
a = 0;
i = 0;
j = 0;
switch(a){
case 1: if(a <1 ){
for(j = 0; j < width; j++){
if (array[i][j] != array[i][j+1]){
printf("error\n");
break;
} else if(j == width) {
a=1;
break;
}
}
}/* End of case 1*/
case 2: if (a > 0 && a < 2){
for(i = 0; i < height; i++){
if (array[i][j] != array[i+1][j]){
printf("error\n");
break;
}else if(i == height) {
printf("No error");
a=2;
break;
}
}
}/* End of case 2 */
case 3:
if (a > 2) {
a=0;
break;
}
}/*End of switch */
printf("It sure is");
}

What Case Means
Just to be clear, in case X, the X is not some label for that case, it's a check of whether the Y in switch(Y) equals X.
To help visualize this, let's rewrite the switch as an if... else statement.
a = 0;
if(a == 1){ // == case 1
// stuff
} else if(a == 2){ // == case 2
// stuff
} else { // == default
...
Those if statements you have in the switch right now have NO bearing on whether that case is executed.
How Switch works
Now, let's talk about how a switch works. When the code is compiled, depending on the range of values for each case, either a jump table or a something virtually identical to a if... else if... else statement is generated. Regardless, you have a list of instructions. The pseudo-assembly looks like this:
instruction n : multiply the value of a by some offset and jump to a*offset + n
n +a*offset_1 : do stuff
jump to m // break
n +a*offset_2 : do stuff
jump to m // break
n +a*offset_3 : do stuff
jump to m // break
n +a*offset_4 : do stuff
jump to m // break
instruction m : do more stuff
If you leave off the breaks,
instruction n : multiply the value of a by some offset and jump to a*offset + n
n +a*offset_1 : do stuff
n +a*offset_2 : do stuff
n +a*offset_3 : do stuff
n +a*offset_4 : do stuff
instruction m : do more stuff
So you can see why the breaks prevent the rest of the cases from being executed - and leaving them out makes that case and every one after it execute, regardless of whether or not you meet the case condition.

in the first case label you ask if a < 1 after getting there with a == 1 so the if is always false.
in the second case, a == 2, so it cannot be equal to 1 (the if checks for a > 0 and a < 2, so it can only be equal to 1 to get into the if)
in the third case you ask for a > 2 (always, as you get there when a == 3) so all the if conditions must be redefined properly.
I suppose you know that you initialize a = 0 and have no case for that value of a, so you are just skipping the switch without entering any of the cases.
You have also not used break; sentences, i suppose purposely, but as you don't have any case for a == 0, you'll never get into any of the switch cases.

Related

Error C2360 Initialization of "arr2" is skipped by "case" tag

I am new to programming.
This is a C language program.
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdbool.h>
#define ture 1
#define false 0
void add(int m, int* arr,int n)
{
if (n == 32) return;
arr[n] += m;
if ( arr[n] > 1)
{
arr[n] = 0;
add(m, arr, ++n);
}
return;
}
int main(void)
{
int T,n,r,m,i,j,k;
bool check = ture;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &r);
switch (r)
{
case 10:
printf("%d", n);
break;
case 2:
int arr2[32] = { 0 };
if (n > 0)
{
for (i = 0; i < 32 ; i++)
{
arr2[i] = n % 2;
n = n / 2;
}
for (j = 31; j >= 0; j--)
{
if (arr2[j] == 0 && check == ture) continue;
else
{
check = false;
printf("%d", arr2[j]);
}
}
}
else if (n == 0)printf("%d", 0);
else if (n < 0)
{
n = -n;
for (i = 0; i < 32; i++)
{
arr2[i] = n % 2;
n = n / 2;
}
for (k = 0; k < 32; k++)
{
arr2[k] = !arr2[k];
}
add(1, arr2, 0);
for (j = 31; j >= 0; j--)
{
if (arr2[j] == 0 && check == ture) continue;
else
{
check = false;
printf("%d", arr2[j]);
}
}
break;
}
case 8:
int arr8[11] = { 0 };
if (n > 0)
{
for (i = 0; i < 11; i++)
{
arr8[i] = n % 8;
n = n / 8;
}
for (j = 10; j >= 0; j--)
{
if (arr8[j] == 0 && check == ture) continue;
else
{
check = false;
printf("%d", arr8[j]);
}
}
}
}
}
return 0;
}
When I run the program in VS2022.There is a bug.
Error C2360 Initialization of "arr2" is skipped by "case" tag Project5 C:\code\C\C_Single\Project5\Project5\test.cpp 74
I don't understand why this is happening.
In my opinion,when I select the contents of case8, I don't need the contents of case2, certainly,including the declaration of arr2.But obviously the compiler doesn't think that way.
So I turn to google for help.
However,google tells me something like this.
Your search - Error C2360 Initialization of "arr2" is skipped by "case" tag - did not match any documents.
Suggestions:
Make sure that all words are spelled correctly.
Try different keywords.
Try more general keywords.
Try fewer keywords.
So I want to get help in stackoverflow.Can anyone help me?
This is one reason that goto statements are frowned upon in modern code.
A case label is not much more that a regular label, and the switch will do something like:
if(value==2) goto label2;
if(value==3) goto label3;
etc.
But when you declare an array like:
int arr[10];
or actually any variable that goes on the stack, the compiler needs to increase the stack pointer to make space for that. in this case:
sp += 10 * sizeof(int)
(Of course this depends on your system/compiler etc)
So what happens if you put this piece of code, in between to (case) labels...
label2:
//int arr[10];
sp += 10*sizeof(int);
label3:
...
// end of scope for arr
sp -= 10*sizeof(int);
// or not?
Yeah it happens only half the time. So now you end up at the end of you switch statement, and your compiler doesn't know weather to decrease the stack pointer or not.
The compiler warns you that the initialization of the array arr2 can be skipped if the control will be passed to the label case 8:. In this case the array will have indeterminate values.
To avoid the compiler message just enclose statements after labels in braces creating a compound statement like for example
case 2:
{
int arr2[32] = { 0 };
//...
}
You have several problems here, within your switch(). (I'm just going to focus on that.)
Firstly, declaring variables within case clauses is problematic: providing them with initialisers, even more so. If you enclose the entire case clause within curly braces, that's a lot better. You also constrain the scope of your case-dependent variables to within that specific case.
Secondly, you have a significant logic error in your switch() statement. Your case 2: clause only hits a break in the n < 0 instance: in all others, it will fall through to case 8:. This is very clearly incorrect.
Thirdly, your case 8: clause has no break statement. As it's the last in the switch(), that's benign - you'll "fall out the bottom", but it's bad practice.
Finally, there is no default: clause. In just about every situation you use a switch() you want to catch the default: case, as it's either going to need a default handling, or it indicates an error condition.
In summary: brace your case clause code, so you can do as you with with, and scope, the variables you declare, and be rigorous about break and default: use. You'll thank me in the future!

How to properly make a counting algorithm to count from file?

This is a program to find the largest even number and its times of occurring from an input file and output it to an output file. I'm having a problem with the output, there seems to be an extra iteration that messes things up.
int main(int argc, char const *argv[])
{
int n, num, i, even, count;
FILE * fptr;
FILE * fptro;
fptr =fopen("maximpar.in", "r");
fptro=fopen("maximpar.out", "w");
/*scanning the first line from the file to get n for for()*/
fscanf(fptr, "%d", &n);
count = 0;
even = INT_MIN;
for(i = 0; i < n; i++)
{
fscanf(fptr, "%d", &num);
if( (num % 2 == 0 && num > even) || (even == num) )
/*checking for largest even number,
not sure about the ..||(even == num) part of the condition*/
{
even = num;
count++;
}
}
fprintf(fptro, "%d %d", even, count);
fclose(fptr);
fclose(fptro);
return 0;
}
Input file
6
9 6 9 8 9 8
Output file
8 3
Why isn't the output file like this? I don't understand
8 2
You need to reset your count whenever you get a new larger number.
I didn't test this, but it should work:
cate = 0;
par = INT_MIN;
for (i = 0; i < n; i++) {
fscanf(fptr, "%d", &b);
// skip odd numbers
if ((b % 2) != 0)
continue;
// get new larger number
if (b > par) {
par = b;
cate = 1;
continue;
}
// increment count on existing largest number
if (b == par)
++cate;
}
UPDATE:
I dont understand why skip iterations explicitly instead of only picking out the iterations that matter? Is there some sort of advantage?
Yes, it's better style. It allows simple single level indented if statements that can have their own comments.
It avoids a messy compound if or a triple level if/else ladder.
IMO, it's a common misconception [particularly among beginning C programmers] that a complex if will execute faster [or is somehow "better"] than several simple ones.
The first if could be thought of a "skip this iteration" test. Here, there's only one. But, for more complex code, there might be several.
The multiple condtion escapes could be handled in a single if with if (c1 || c2 || c2 || ... || c10) continue; but that gets messy fast.
Herein, for properly indented if/else ladder logic, we'd need:
if (cond1)
do_stuff1;
else
if (cond2)
do_stuff2;
else
if (cond3)
do_stuff3;
If we're not in a loop, here's a "trick" to avoid if/else ladder logic, by using do { ... } while (0);:
do {
if (cond1) {
do_stuff1;
break;
}
if (cond2) {
do_stuff2;
break;
}
if (cond3) {
do_stuff3;
break;
}
} while (0);
enclose the condition
if( ( ...&&...) ||(....) )
The answer is because count was incremented from 0 to 1 when b = 6. 2 iterations later, b = 8 and now count = 2, and 2 iterations after that, b = 8 and count = 3.
I also recommend you nest your if statement in parentheses for readability. Commenting would help too :) I'm a stats guy, and I have no idea what you are doing based on your variables' names.
You need to reset your counter inside the if block if b > par.
Like:
if( num % 2 == 0 && num >= even) {
if (num > even){
even = num;
count = 1;
} else {
count++;
}
}
Thanks.
JK

Why does my function always return 1?

I'm writing a function that's supposed to check whether there is a winner or not in a game of "noughts and crosses", or "three in a row".
The game works by first drawing out 3 x 3 squares in the command prompt. The user then moves the cursor between the squares, and presses enter to place an "X". The next selected square gets an "O" placed in it, and then an "X" again, and so on. After turn 5 (the first possible turn there could be a winner) the program checks if there is a winner after every turn, and if none is found after 9 turns (when all squares have something in them) the program declares a draw.
However, the function I've written to check for a winner always returns 1 when it's called, which means there is a winner (X more specifically, since thatäs the one that made the last move). Therefore the game ends on turn 5, no matter what the squares contain.
Here is my code:
int control(char p[3][3]) {
int i;
for (i = 0; i <= 3; i++) //Checks if any of the horizontals have 3 of the same markers in a row
if (p[i][1] == p[i][2] && p[i][2] == p[i][3])
return 1;
for (i = 0; i <= 3; i++) //Checks if any of the vertical columns have 3 of the same markers
if (p[1][i] == p[2][i] && p[2][i] == p[3][i])
return 1;
else if (p[1][1] == p[2][2] && p[2][2] == p[3][3]) //Checks if top left, middle and bottom right squares have the same marker
return 1;
else if (p[3][1] == p[2][2] && p[2][2] == p[1][3]) //Checks if the top right, middle and bottom left have the same marker
return 1;
else //If none of the above have the same 3 markers, the game keeps going
return 0;
}
You are passing in a 3x3 array (with indices 0, 1 and 2 in each dimension), but in your loops you are iterating 4 times (indices 0, 1, 2 and 3). Try for (i = 0; i < 3; i++) in your loops instead, as your loops will now check values beyond the boundaries of the p array, and if you are unlucky the contents of that memory causes your control function to return 1.
Finally, I think the final else-block should not be in the loop, but rather outside of it: If both loops have run and you have not returned yet, you can safely return 0, but you wouldn't want to return a 0 prematurely before you have checked all your verticals.
Here is the function with the changes to the indices and the diagonal checks and final else-block fished out of the second for-loop:
int control(char p[3][3]) {
int i;
/* Check horizontals */
for (i = 0; i < 3; i++)
if (p[i][0] == p[i][1] && p[i][1] == p[i][2])
return 1;
/* Check verticals */
for (i = 0; i < 3; i++)
if (p[0][i] == p[1][i] && p[1][i] == p[2][i])
return 1;
/* Check diagonals */
if (p[0][0] == p[1][1] && p[1][1] == p[2][2])
return 1;
if (p[2][0] == p[1][1] && p[1][1] == p[0][2])
return 1;
return 0;
}

C: realloc works on Linux, but not on Windows

this is my first question on Stack Overflow, sorry if it's not well written.
I have a little problem. I wrote a program in C (I'm currently learning C, I am a newbie, my first language, don't say I should've learnt Python, please, because I'm doing just fine with C). So, I wrote this little program. It's an attempt of mine to implement a sorting algorithm (I made the algorithm myself, with no help or documentation, it's very inefficient I think, I was just fooling around, though I don't know whether the algorithm already exists or not). The only sorting algorithm I know is QuickSort.
In any case, here is the final program (has plenty of comments, to help me remember how it works if I'll ever revisit it):
// trying to implement my own sorting algorithm
// it works the following way:
// for an array of n integers, find the largest number,
// take it out of the array by deleting it, store it
// at the very end of the sorted array.
// Repeat until the original array is empty.
// If you need the original array, simply
// make a copy of it before sorting
/***************************************/
// second implementation
// same sorting algorithm
// main difference: the program automatically
// computes the number of numbers the user enters
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
int *sort(int *a, int n); // sort: the actual sorting function
char *read_line(char *str,int *num_of_chars); // read_line: reads input in string form
int *create_array(char *str, int n); // create_array: counts the num of integers entered and extracts them
// from the string the read_line function returns, forming an array
int size_of_array_to_be_sorted = 0; // of integers
int main(void)
{
int *array, i, *sorted_array, size = 3;
char *str = malloc(size + 1);
if (str == NULL)
{
printf("\nERROR: malloc failed for str.\nTerminating.\n");
exit(EXIT_FAILURE);
}
printf("Enter the numbers to be sorted: ");
str = read_line(str, &size);
array = create_array(str, size + 1);
sorted_array = sort(array, size_of_array_to_be_sorted);
printf("Sorted: ");
for (i = 0; i < size_of_array_to_be_sorted; i++)
printf("%d ", sorted_array[i]);
printf("\n\n");
return 0;
}
int *sort(int *a, int n)
{
int i, j, *p, *sorted_array, current_max;
sorted_array = malloc(n * (sizeof(int)));
if (sorted_array == NULL)
{
printf("ERROR: malloc failed in sort function.\nTerminating.\n");
exit(EXIT_FAILURE);
}
for (i = n - 1; i >= 0; i--) // repeat algorithm n times
{
current_max = a[0]; // intiliaze current_max with the first number in the array
p = a;
for (j = 0; j < n; j++) // find the largest integer int the array
if (current_max < a[j])
{
current_max = a[j];
p = (a + j); // make p point to the largest value found
}
*p = INT_MIN; // delete the largest value from the array
sorted_array[i] = current_max; // store the largest value at the end of the sorted_array
}
return sorted_array;
}
char *read_line(char *str, int *num_of_chars)
{
int i = 0; // num of chars initially
char ch, *str1 = str;
while ((ch = getchar()) != '\n')
{
str1[i++] = ch;
if (i == *num_of_chars) // gives str the possibility to
{ // dinamically increase size if needed
str1 = realloc(str, (*num_of_chars)++);
if (str1 == NULL)
{
printf("\nERROR: realloc failed in read_line.\nTerminating.\n");
exit(EXIT_FAILURE);
}
}
}
// at the end of the loop, str1 will contain the whole line
// of input, except for the new-line char. '\n' will be stored in ch
str1[i++] = ch;
str1[i] = '\0'; // store the null char at the end of the string
return str1;
}
int *create_array(char *str, int n)
{
int *array, i, j, k, num_of_ints = 0;
for (i = 0; i < n; i++) // computing number of numbers entered
if (str[i] == ' ' || str[i] == '\n')
num_of_ints++;
array = calloc((size_t) num_of_ints, sizeof(int)); // allocacting necessary space for the array
if (array == NULL)
{
printf("\nERROR: calloc failed in create_array.\nTerminating.\n");
exit(EXIT_FAILURE);
}
k = 0;
i = 1; // populating the array
for (j = n - 1; j >= 0; j--)
{
switch (str[j])
{
case '0': case '1': case '2':
case '3': case '4': case '5':
case '6': case '7': case '8':
case '9': array[k] += ((str[j] - '0') * i);
i *= 10;
break;
case '-': array[k] = -array[k]; // added to support negative integers
default: i = 1;
if (str[j] == ' ' && (str[j - 1] >= '0' && str[j - 1] <= '9'))
/* only increment k
*right before a new integer
*/
k++;
break;
}
}
// the loop works in this way:
// it reads the str string from the end
// if it finds a digit, it will try to extract it from the
// string and store in array, by adding to one of the elements
// of array the current char - ASCII for '0', so that it actually gets a digit,
// times the position of that digit in the number,
// constructing the number in base 10: units have 1, decimals 10, hundreds 100, and so on
// when it finds a char that's not a digit, it must be a space, so it resets i
// and increments k, to construct a new number in the next element of array
size_of_array_to_be_sorted = num_of_ints;
return array;
}
I've written everything myself, so if you think I use some bad methods or naive approaches or something, please tell me, in order for me to be able to correct them. Anyways, my problem is that I have these 'try to handle errors' if statements, after every call of malloc, calloc or realloc. I have a Linux machine and a Windows one. I wrote the program on the Linux one, which has 4GB of RAM. I wrote it, compiled with gcc, had to change a few things in order to make it work, and it runs flawlessly. I have no problem. I then copied it onto a USB drive and compiled it with mingw on my Windows machine, which has 8GB of RAM. I run it, and if I give it more than 3 2-digit integers, it displays
ERROR: realloc failed in read_line.
Terminating.
At least I know that the 'error handling' if statements work, but why does this happen? It's the same code, the machine has twice as much RAM, with most of it free, and it runs with no problem on Linux.
Does this mean that my code is not portable?
Is it something I don't do right?
Is the algorithm wrong?
Is the program very, very inefficient?
Sorry for the long question.
Thanks if you wanna answer it.
The line in question is:
str1 = realloc(str, (*num_of_chars)++);
where *num_of_chars is the current size of str. Because you are using post-increment, the value passed for the new allocation is the same as the current one, so you haven't made str any bigger, but go ahead and act as if you had.

When conditions in a if statement are met inside a for loop, how can I print one result?

Basically I have the following code. The problem is that I only want to have "Pass" printed once if both conditions in the if statement are met. The int 'res' is an average of all 6 elements in the parts array. Therefore, all "parts" must have a value of at least 40 and the average of these parts, known as "res", must also be above 40. At the moment the code obviously outputs Pass for each of the 6 elements of the "parts" array if they are over 40. I want this to just however output Pass once if all six elements of the "parts" array and "res" are over or equil to 40.
Any help will be gratefully appreciated!
for (int i = 0; i < 6; i++)
{
if (res >= 40 && parts[i] >= 40)
{
System.out.println("Pass");
}
}
2 things:
1) You look like you're just checking for a negative case. If you find any values that are less than 40 you want to break and not print "Pass". If each element is over 40 and res is over 40 you want to continue until you either find one that isn't or finish through the list. If you get through the whole list and none failed you know you can print "Pass".
2) res isn't changing in your loop as you supplied it. If you are changing it in the loop and this is just example code that's fine. But if you're not you should really just check it once outside of the loop.
boolean print = true;
for (int i = 0; i < 6; i++)
{
if (res < 40 | parts[i] < 40)
{
print = false;
break;
}
}
if(print)
System.out.println("Pass");
If I am understanding your question correctly, you would want to put
break;
after the println
for (int i = 0; i < 6; i++)
{
if (res >= 40 && parts[i] >= 40)
{
System.out.println("Pass");
break;
}
}
You can use a break; statement for step out of your loop after you print to the console.
A break is used to step out of any kind of loop.
while(true){
//do stuff
if(condition){
break;
}
}

Resources