Memory error in C program, The name disappears? - c

Im trying to make a simple game, http://pastebin.com/BxEBB7Z6, in c. The goal is to beat the computer by getting as close to 21 as possible by getting random numbers.
For each round the players name and sum is presented, but for some reasons it only works that first time? Something like this:
Player John has sum 0.
Player has sum 9.
Player has sum 11.
And so on.
Why does the the player's name get showed once, but not any other prints after that? I dont do a reassign somewhere :-)
I use the function void PrintPlayerSum(struct Player *p) to print it out, it works the first time, but only that.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Player
{
char name[256];
int sum;
};
void PrintPlayerSum(struct Player *p)
{
printf("Player %s has sum %d\n", p->name, p->sum);
}
void wait ( int seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
int main()
{
struct Player *player = malloc(sizeof(*player));
strcpy( player->name, "John");
player->sum = 0;
while(1)
{
PrintPlayerSum(player);
printf("Do you want another number? (y/n, q for quit) ");
char ch;
scanf("%s", &ch);
if( ch == 'q' )
break;
if( ch == 'y' )
{
srand(time(NULL));
int rnd = rand() % 13 + 1;
player->sum += rnd;
printf("Player got %d\n", rnd);
}
if( ch == 'n' || player->sum > 21)
{
if( player->sum > 21 )
{
printf("\n*** You lost the game, please try again... ***");
}
else
{
printf("\nCPU's turn\n");
int cpusum = 0;
while( 1 )
{
if( cpusum > 21 )
{
printf("\n*** CPU lost the game with the score %d, you win! ***", cpusum);
break;
}
if( cpusum > player->sum )
{
printf("\n*** CPU won the game with the score %d, please try again ***", cpusum);
break;
}
wait(1);
srand(time(NULL));
int rnd = rand() % 13 + 1;
cpusum += rnd;
printf("CPU got %d, sum is %d\n", rnd, cpusum);
}
}
break;
}
printf("\n\n");
}
/* Cleanup ******************/
free(player);
/****************************/
printf("\n\n\n");
system("PAUSE");
return 0;
}

I suspect the problem is your use of scanf. You say you want to read a zero-terminated string, but you stuff it into a single char. The way the variables are laid out on the stack causes the terminating zero-byte to end up as the first char in player->name.
Try typing "buffer overflow" instead of "y", and you should get "player uffer overflow go ...".
If you want to stick with scanf, you want to make sure you pass it a proper string and set a limit on the size of the target buffer. For reading one char, try fgetc.
Edit:
The above is of course not quite right... It is a buffer overflow, but it is the pointer of the player struct that is being overwritten. By lucky coincidence you get to a valid address that points to a zero-byte. By typing more, you will most likely get a crash instead.

Your scanf call is likely the problem:
scanf("%s", &ch);
You seem to want a single character, but you're reading a string. It'll put the first character in ch, but keep going from there and overwrite whatever's next on the stack.
You should probably just use fgetc(stdin) or another function that reads a single character, if a single character is what you want.

shouldn't it be
struct Player *player = malloc(sizeof(struct Player));

Weird thing like that are usually caused by writing to unallocated memory. (Usually writing beyond the end of an array.)
I didn't look at your code, but search for things like that. Then run your program under valgrind.

At a first glance i can see you have done:
scanf("%s", &ch);
Which will use the address of ch to input a string, and therefore result in a buffer overflow. You need to do
ch = getchar ();
scanf ("%c", &ch);
etc.

Related

Output not showing in C

I'm writing a code that must identify the letter 't' or 'T' in a word, before or after the middle of it.
If the first half of the word does contain a 't' or a 'T', the program should output a 1. If the first half does not contain the letter 't' or 'T', but the second half does, then the program should output a 2. Otherwise, if there is no 't' or 'T' in the word at all, the program's output should be -1. The word entered will not have more than 50 letters.
#include <stdio.h>
#include <string.h>
int main() {
char word[50];
int i = 0, length, t = 0, T = 0;
scanf("%s", word);
length = strlen(word);
t = word[i] == 't';
T = word[i] == 'T';
while(!t || !T) {
if((t || T) && i <= length / 2) {
printf("%d", '1');
} else if((t || T) && i > length / 2) {
printf("%d", '2');
//}else{
// printf("%d", '-1');
}
i++;
}
return 0;
}
If I enter any word and press enter, nothing is printed. Another thing is that when I remove the comment slashes from the two lines at the bottom, the program goes through an infinite loop.
Could someone please help?
This sounds like a school assignment, so I'll focus on advising/critiquing your code rather than giving a solution.
The first recommendation I have is to use a for loop instead of a while loop. A Rule of thumb in C is to only use a while loop when you actually don't have any idea how many things you need your program to look at.
You already have the length of the string, so set up your for loop to loop exactly once for each character.
Next you need to change how you are using printf. The %d format specifier is for printing integers, but you are passing it '1'. This is not an integer, it is the ascii representation of the symbol 1 (which is actually has the value 49, see the ascii table for more info)
You can either pass printf the value 1, or use the %c specifier, which expects ascii characters.
Better yet, just say printf("1");
That doesn't get you all the way there, but I think it lays the ground work so you can find the solution!
Condition !t || !T has no sense to be used as loop condition ...ask yourself how the loop will end ? you need just to check i is less than length
Second, the assignments t = word[i] == 't'; T = word[i] == 'T'; outside the loop have no sense ...you will be just pointing to the zero index of the string ...you should check all characters
third , the printf lines need to use %d
fourth , you appear not getting the purpose of the program printing inside loop will lead to printing many numbers and you just want to know if there is t or T you need to print single line.you may use variable int result=0; to hold the value you want and print it in the end ...of course you will need using break statement in the if((t || T) && i <= length / 2) and if((t || T) && i > length / 2) because no need for more searching
fifth, you should re-read , re-think , re-code the assignment before going bored and asking about it
sixth, there is a working version by modifying your code but you should try writing a good solution before looking at a solution as it better to solve your problems by yourself
#include <stdio.h>
#include <string.h>
int main() {
char word[50];
int i = 0, length, t = 0, T = 0;
scanf("%s", word);
length = strlen(word);
int result=0;
while( i<length) {
t = word[i] == 't';
T = word[i] == 'T';
if((t || T) && i <= length / 2) {
result=1;
break;
} else if((t || T) && i > length / 2) {
result=2;
break;
}else{
result=-1;
}
i++;
}
printf("%d",result);
return 0;
}
# include <stdio.h>
int main()
{
char name[20];
int age;
int siblings;
int childrens;
printf ("Hello my name is A.I, what is your name? \n");
scanf("%s", &name);
printf("how old are you : \n");
scanf("%d",&age);
printf("how many siblings you have: \n");
scanf("%d", &siblings);
printf("how many children you have: \n");
scanf("%d", &childrens);
printf("so your name is : %s \n", name);
printf("and your age is : %d \n", age);
printf("you have siblings : %d\n", siblings);
printf("so you have childrens : %d\n", childrens);
return 0;
}

Guess a person's secret number between 0 - 100 using binary search

I converted a code that I know how to construct in python in C Language, but everytime I run the program in CodeBlocks, the program crashes! And I have NO idea why this is happening, can someone help me?
The program is suppose to guess a person's number (between 0 - 100), using binary search.
For example, if my number is 66, the program asks if my number is 50, since 66 is higher than 50, the number 50 becomes the lower boundary while 100 remains to be the higher boundary, and so on...
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int x;
printf("Please think of a number between 0 and 100\n\n");
x = binarysearch();
printf("%d", x);
}
int binarysearch()
{
int hi,lo,guess;
hi = 100;
lo = 0;
char user_inp;
while (1){
guess = round(((hi + lo)/2));
printf("Is your secret number %d?\n\n", guess);
printf("Enter 'h' to indicate the guess is too high. \nEnter 'l' to indicate the guess is too low.\nEnter 'c' to indicate I guessed correctly. \n");
scanf("%c", &user_inp);
if (strcmp(user_inp, "c") == 0){
break;
}
else if (strcmp(user_inp, "h")==0){
hi = guess;
}
else if (strcmp(user_inp, "l")==0){
lo = guess;
}
else{
printf("Sorry, I did not understand your input.");
continue;
}
}
printf("Game over. Your secret number was");
return guess;
}
As per the comments, the problem was very likely the incorrect use of strcmp:
char *string = "fish";
char not_a_string = 'f';
if (0 == strcmp( not_a_string, string ))
...
The character 'f' has ASCII value 0x66. strcmp would blindly use this as a pointer (expecting it to point to a valid string) which would cause a crash as you access memory that's not yours (a segmentation fault).
You would have got away with strcmp( &not_a_string, string ) in this case, but that's good fortune, not correct code.
To compare the user's character input with another character, you can just use a straightforward equality (since they're both really integers):
if ( user_inp == 'c' ) ...
So that's your code fixed, but how did you ever get to run it in the first place? For me GCC immediately complained:
In function 'int binarysearch()': so.cpp:17:29: error: invalid conversion from 'char' to 'const char*' [-fpermissive]
if (strcmp(user_inp, "c") == 0){
and didn't produce an output. It's telling you the same thing I just did (albeit fractionally more cryptically).
Lessons to learn: listen to your compiler's complaints (and make your compiler as complainy as possible)
#pmg also noted:
add a space before the conversion specifier: scanf(" %c", &user_inp)
Without it, every time you hit Enter:
Sorry, I did not understand your input.Is your secret number 25?
ie you get a spurious complaint. But with the space it works as desired.
(I hate scanf, so have no idea why this works ;) )
Your binary search is incorrect, you need to swap the check of 'h' and 'l'.
Because you compare chars and not strings, use == and not strcmp().
You don't need to include <math.h> because guess is an int, so it'll automatically round floats.
You can use getchar() to clear the buffer after the scanf()
You need to declare your function before main (possibly by defining the function before main).
#include <stdio.h>
#include <stdlib.h>
// WITHOUT <MATH.H>
int binarysearch(void);
int main(void)
{
int x;
printf("Please think of a number between 0 and 100\n\n");
x = binarysearch();
printf("%d", x);
return 0; // RETRUN 0
}
int binarysearch(void)
{
int hi,lo,guess;
hi = 100;
lo = 0;
char user_inp;
int flag = 1; // USE FLAG, NOT BREAK AND CONTINUE
while (flag){
guess = ((hi + lo)/2); // WITHOUT ROUND
printf("Is your secret number %d?\n\n", guess);
printf("Enter 'h' to indicate the guess is too high. \nEnter 'l' to indicate the guess is too low.\nEnter 'c' to indicate I guessed correctly. \n");
scanf("%c", &user_inp);
getchar(); // CLEAR THE BUFFER
if (user_inp == 'c'){ // MAKE FLAG 0
flag = 0;
}
// USE '==', NOT STRCMP
else if (user_inp == 'l'){ // YOU NEED TO SWAP 'L' & 'H'
hi = guess;
}
else if (user_inp == 'h'){
lo = guess;
}
else{
printf("Sorry, I did not understand your input.");
}
}
printf("Game over. Your secret number was ");
return guess;
}

C Program, getting error about uninitialized variable, the program never ends

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
#define MAXGUESSES 5
void Instructions();
int PlayGuess(char solution);
char GetLetter();
int CompareLetters(char guess, char solution);
int main()
{
int i = 0;
int numgames = 0;
char solution;
char guess;
int compareletter(char guess, char solution);
FILE *inp;
inp = fopen("letterList.txt", "r");
fscanf(inp, "%c", &solution);
Instructions();
//get number of games the user wants to play
printf("Please enter the number of games you want to play\n");
scanf("%d", &numgames);
for (i = 1; i <= numgames; i++)
//print current game (value of i)
{
//get letter to guess from file
fscanf(inp, "%c", &solution);
PlayGuess(solution);
printf("\nThe letter is %c\n", solution);
}
fclose(inp);
}
void Instructions()
{
printf("Welcome to Letter Guess\n");
printf("To begin you will enter the number of games you want to
play(1 – 4 games)\n");
printf("You have 5 chances to guess each letter\n");
printf("Let's begin\n");
}
int PlayGuess(char solution) //player defined guesses.
{
int numGuesses = 0;
int winOrLose = 0;
while (numGuesses < MAXGUESSES)
{
GetLetter();
numGuesses = numGuesses + 1;
if (numGuesses>MAXGUESSES)
{
printf("You have run out of guesses\n");
}
}
return 0;
}
//get the guess from the user (call GetLetter function)
//call compareLetters function
char GetLetter()
{
char guess = 0;
char solution;
printf("Enter a guess:", guess);
scanf(" %c", &guess);
CompareLetters(guess, solution);
return guess;
}
//compare the guess and the solution
//return a 1 if they are the same
// message based on before or after alphabetically
//return a 0 if the guess and answer are not the same
int CompareLetters(char guess, char solution)
{
if (guess == solution) //if answer is correct
{ printf("Thats it!\n");
return 1;
}
else
if (guess<solution)
{
printf("The letter you are trying to guess comes after %c\n", guess);
printf("\nTry again\n");
GetLetter();
return 0;
}
else
if (guess>solution)
{ printf("The letter you are trying to guess comes before %c", guess);
printf("\nTry again\n");
GetLetter();
return 0;
}
}
Sorry if the code is a bit messy.
Problem #1: The variable "solution" is uninitialized but i do not know how to fix it. I have this problem a lot, if possible i could use an explanation.
Problem #2: When i launch the program and enter the amount of games I want to play it ignores it and gives me endless guesses, the program never stops.
Thanks.
Just put char solution = '\0';. It's enough to get rid of warning.
Try printing the value of numgames you've just read in scanf() function. It seems you're getting some invalid value for some reason...
Upd: I see your problem: you're calling GetLetter() from PlayGuess(); and you're calling CompareLetters() from GetLetter(); and then you call GetLetter() from CompareLetters() so you create endless recursion. Remove calls GetLetter() from CompareLetters().
Continuing from my comments, the key takeaways from your code are (1) you cannot learn C by guessing at syntax, compiling, over and over again, (2) validate ALL input to your program by checking the return of all input functions and validating the value you receive, (3) enable compiler warnings and then read, understand and correct each warning before attempting to compile again, and (4) do not accept code until it compiles cleanly, without warning.
Since your code includes #define _CRT_SECURE_NO_WARNINGS, it is apparent you are on windows using cl.exe (either from cmd.exe or from VS-Code). For learning basic programming, close VS-Code, open the Command Line provided by your VS (or SDK) install, and don't worry about using the IDE again, until you have mastered compiling from the command line and understand your compiler options. See cl.exe C/C++ Compiler Options, or type cl /? at the command prompt.
From the command line, your basic compile string should be similar to:
cl.exe /nologo /W3 /Ox /Tc mysource.c
(/W3 enable most warnings, /Ox enable all optimizations)
I find it helpful to not clutter my c-source directory with .obj and .exe files so I create two additional directories /obj and /bin for the object and executable files. You then use the /Fo and /Fe options to tell the compiler to put the object files and exe files in the proper directories, e.g.
cl /nologo /W3 /Ox /Foobj/mysource /Febin/mysource /Tc mysource.c
That will put mysource.obj in the obj directory and mysource.exe in the bin directory.
You must have the logic for your code clear in your head before you sit behind the keyboard and start pecking away. (See: (1) above). The easiest way to keep it straight by drawing a simple logic diagram for your code and identify what values you will handle in main() and then what will be handled in each function(). You don't need anything fancy, an 8.5x11 sheet of paper and pencil will do. After you have a clear road map for what each part of your code will do, then sit down and start pecking away.
Putting that logic to test, you can rework your code so it makes a lot more sense than it currently does, e.g.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
#define MAXGUESSES 5
void Instructions();
int PlayGuess (char solution);
char GetLetter();
int CompareLetters (char guess, char solution);
int main (void)
{
int i = 0,
numgames = 0;
char solution;
FILE *inp = fopen ("letterList.txt", "r");
if (inp == NULL) {
fprintf (stderr, "error: file open failed 'letterList.txt'.\n");
return 1;
}
Instructions(); /* give instructions */
/* get number of games the user wants to play */
printf("Please enter the number of games you want to play: ");
if (scanf ("%d", &numgames) != 1) {
fprintf (stderr, "error: invalid input - numgames.\n");
return 1;
}
putchar ('\n');
for (i = 0; i < numgames; i++)
{
/* get letter to guess from file */
if (fscanf (inp, " %c", &solution) == EOF || solution < ' '
|| '~' < solution) {
fprintf (stderr, "error: invalid character - solution.\n");
return 1;
}
printf (" ==> Game %d <==\n\n", i + 1);
PlayGuess (solution);
printf("The letter was '%c'!\n\n", solution);
}
fclose (inp);
return 0; /* main() is type int and returns a value */
}
void Instructions()
{
printf ("Welcome to Letter Guess\n"
"To begin you will enter the number of games you want "
"to play (1 – 4 games)\n"
"You have 5 chances to guess each letter\n"
"Let's begin\n\n");
}
int PlayGuess (char solution)
{
int numGuesses = 0;
char guess;
while (numGuesses < MAXGUESSES)
{
guess = GetLetter();
if (CompareLetters (guess, solution))
return 1;
numGuesses = numGuesses + 1;
}
printf ("You have run out of guesses\n");
return 0;
}
/* get a letter and validate it is good */
char GetLetter()
{
char guess = 0,
tmp;
printf ("Enter a guess: ");
if (scanf (" %c", &tmp) != EOF && ' ' <= tmp && tmp <= '~')
guess = tmp;
return guess;
}
/* compare the guess and the solution
* return a 1 if they are the same
* message based on before or after alphabetically
* return a 0 if the guess and answer are not the same
*/
int CompareLetters(char guess, char solution)
{
if (guess == solution) /* answer is correct */
{
printf ("Thats it!\n\n");
return 1;
}
if (guess < solution)
printf ("The letter you are trying to guess comes after '%c'\n",
guess);
else
printf ("The letter you are trying to guess comes before '%c'\n",
guess);
printf ("Try again\n\n");
return 0;
}
Example Compile String for cl.exe (VS)
>cl /nologo /W3 /Ox /Foobj/guessletter /Febin/guessletter /Tc guessletter.c
Example Use/Output
> bin\guessletter.exe
Welcome to Letter Guess
To begin you will enter the number of games you want to play (1 – 4 games)
You have 5 chances to guess each letter
Let's begin
Please enter the number of games you want to play: 2
==> Game 1 <==
Enter a guess: k
The letter you are trying to guess comes before 'k'
Try again
Enter a guess: c
The letter you are trying to guess comes after 'c'
Try again
Enter a guess: d
Thats it!
The letter was 'd'!
==> Game 2 <==
Enter a guess: e
The letter you are trying to guess comes after 'e'
Try again
Enter a guess: g
The letter you are trying to guess comes before 'g'
Try again
Enter a guess: f
Thats it!
The letter was 'f'!
Look things over and think about how to approach programming in C. It is an exact language. It is up to you to account for all characters in all input buffers as well as your memory use. If you don't know what parameters a library function takes, or what type and value it will return, or how to use it, look it up. The man pages are available at, e.g. msdn fscanf, fwscanf or scanf(3): input format conversion)
Let me know if you have further questions.
Accepting Input In Any Case, Converting to Lowercase
To accept input in any case and convert the value to lowercase so that guess is always lowercase in your code, you need to change only one-line:
/* get a letter and validate it is good
* (convert letter to lowercase)
*/
char GetLetter()
{
char guess = 0,
tmp;
printf ("Enter a guess: ");
if (scanf (" %c", &tmp) != EOF && ' ' <= tmp && tmp <= '~')
guess = tolower (tmp);
return guess;
}
note: For ASCII characters, the 6th-bit is the 'case bit', if it is 1, the character is lowercase, 0 uppercase. tolower can simply be written as:
unsigned c_tolower (unsigned c)
{
if ('A' <= c && c <= 'Z')
c ^= (1 << 5);
return c;
}
You have to initialize guess and solution to something before you use them in a function.
And what does this line
int compareletter(char guess, char solution);
indicate, there is no function with same name nor it is a call to any function.
In case for dummy initialization you can use
solution = '\0';

Geting some garbage value on the second index

I'm trying to calculate HCF in C with pointers.
int-type-Pointer ptr points to an array of integers.
The inputs that i have given are 30,60,18,a. And here "a" is to terminate the list of integers and breaks off the "while".
I tried the debug mode, and found the values:
*ptr = 30
*(ptr+1)= -1163005939 //the garbage that i'm talking of.
*(ptr+2)= 60
*(ptr+3)= 30
while what i should get are 30, 60,18.
#include<stdio.h>
void main(){
int* ptr=(int*) malloc( sizeof(int)* 50);
int input=0;
int smallest;
printf ("Enter the numbers (press any alphabet when you're done )\n");
while (1)
{ input++;
if (input==1 && scanf("%d", ptr)) // the first number is stored in smallest
{smallest = *ptr; continue;}
if (!scanf("%d",ptr+input )) // if the input is a character , scanf says 0,
{input--; //! makes it 1, and we jump out of the loop
break;}
if (smallest > *(ptr+input)) // swapping
{ smallest += *(ptr+input);
*(ptr+input) = smallest- *(ptr+input);
smallest= smallest- *(ptr+input);
}
}
// code for determining the HCF
char c;
if (smallest <=0)
{
printf("", scanf("%c",&c ), printf("Answer is 0")); // it will print that the answer
exit(0); //is 0 then waits for you to
} //press any key and then it exits
//if smallest greater than 0
int i=2;
int HCF=1;
int j;
for (; i<smallest/2; i++)
{ for (j=0; j<=input;j++)
// this is where the problem is suspected
//as i ve seen in the debug mode
//it gives results divides the garbage value to i
{if (! (*(ptr+j)%i == 0)) // if the number stored in the location is not
break; //divisible by i, then leave that number i
} //and check for the next i
if (j>input)
HCF *= i;
}
printf( "", scanf("%c", c), printf("The HCF is %d ", HCF));
free(ptr);
}
So what is the problem?
And i didnt want to allocate the 50 ints memory. I wanted to just use the pointer wildly without any allocation. I know its bad practice but i just want to apply it . Is that any harm to other programs? How?
It's garbage because you never write anything to it. Look at this code
while (1)
{ input++;
if (input==1 && scanf("%d", ptr)) // the first number is stored in smallest
{smallest = *ptr; continue;}
if (!scanf("%d",ptr+input )) // if the input is a character , scanf says 0,
{input--; //! makes it 1, and we jump out of the loop
break;}
//code that doesn't assign values to ptr
}
by the time you get to scanf("%d",ptr+input ), input will be 2 if scanf("%d", ptr) returned a truthy value. That's because of this if statement:
if (input==1 && scanf("%d", ptr)) // the first number is stored in smallest
{smallest = *ptr; continue;}
notice how you continue here when input is equal to 1? that means that the while loop will skip everything else and begin again from the beginning, and the first thing that it's going to do is increment input from 1 to 2.

Why does this C program go pear-shaped? Have I broken my buffers?

I've been experimenting with C a little bit. I usually use PHP and javascript.
I did "Hello World" and then I typed in this, which I copied from a website somewhere...
#include <stdio.h>
#include <stdlib.h>
#define MAX 20
int intcmp(const void*v1, const void *v2){
return (*(int *)v1 - *(int *)v2);
}
main(){
int arr[MAX], count, key , *ptr;
printf("Enter %d integer values; press enter after each\n", MAX);
for (count = 0; count < MAX; count++)
scanf("%d", &arr[count]);
puts("Press a key to sort the values");
getc(stdin);
qsort(arr, MAX, sizeof(arr[0]), intcmp);
for(count=0; count < MAX; count++)
printf("\narr[%d] = %d.", count, arr[count]);
puts("\nPress a key to continue");
getc(stdin);
printf("Enter a val to search for");
scanf("%d", &key);
ptr = (int * )bsearch(&key, arr, MAX, sizeof(arr[0]), intcmp);
if(ptr != NULL){
int fred = (ptr - arr);
printf("%d found at arr[%d]", key ,fred);
}else{
printf("%d not found", key);
}
}
So far so good. I'm trying to understand what all the stars do, but it's falling into place (ha ha - falling stars :)
However, if I type in a float e.g. 21.45 when it asks me for 20 integers, it rushes through to "Enter a val to search for" having filled the 20 array values with weird numbers.
Have I created some sort of buffer overflow? I realise that input should be checked - but I'm interested to know what I've done. Could I use my program to run arbitrary code? (Well, no, not with my knowledge... but could someone?)
However, if I type in a float e.g. 21.45 when it asks me for 20 integers, it rushes through to "Enter a val to search for" having filled the 20 array values with weird numbers
If you enter a value such as 21.45 the call to scanf("%d") will fail, as it is not an int, and will leave the .45 in stdin (the 21 will be extracted as a valid int) to be processed again. This causes the loop to re-read this value again and again (as it fails every time). The weird numbers are due to the elements of the array being uninitialised.
Check the return value of scanf() which returns the number of assignments made and if it fails skip whatever is in stdin:
int count = 0;
while (count < MAX)
{
if (1 == scanf("%d", &arr[count]))
{
count++; /* OK, so get next. */
}
else
{
/* !OK, skip invalid input. */
int c;
while ((c = fgetc(stdin)) != EOF && c != '\n');
}
}
If you fill the standard input with something that's not in the right format (in this case a float), the extraction of the value will fail. However, the broken data won't get extracted from the input stream. This means that scanf will fail repeatedly. As such, your arr[0...MAX-1] is not filled at all by scanf.
If you want to get a float, then in the scanf you need to have:
scanf("%f", &arr[count]);
Additionally, you need to declare your array as float arr[MAX]

Resources