Load Array Elements Using Function - c

I am trying to load elements into an array using a function but I don't know what I'm doing wrong. I want to load elements from a data file until -1 is entered. Here is what I have and I don't know what to do from here.
#include <stdio.h>
/*Function to scan in grades*/
int LoadArray (int grade[ ])
{
int i = 0;
while(scanf("%i", grade[i]) != -1) {
i++;
}
return i;
}
/*Main program*/
int main (void)
{
int grade[200], count=0;
/*Call function*/
count = LoadArray(grade);
printf("%i", count);
return 0;
}

Two problems.
1) You're missing an ampersand:
scanf("%i", &grade[i]);
you need to pass the address of the variable scanf should put the result in. You were passing the contents of grade[i] instead, and reading uninitialized memory is undefined behavior.
2) scanf doesn't return the value it read from stdin; you should compare the variable you read to -1. Also, it's bad practice to pass an array to a function but not its size, as then the function has no way of knowing how big the array is.
To sum up, the code with fixes looks like this:
/*Function to scan in grades*/
int LoadArray(int grade[], size_t gradeMaxCount)
{
int i = 0;
while (1)
{
int tmp;
if (i >= gradeMaxCount || scanf("%i", &tmp) != 1 || tmp == -1)
break;
grade[i++] = tmp;
}
return i;
}
Call the function like this:
count = LoadArray(grade, sizeof(grade) / sizeof(grade[0]));
Note that funny things will happen if i somehow becomes negative. You could make it size_t instead (this would also require you to change the function return type and print it using %zu), depending on how much of a purist you are.

int LoadArray (int grade[ ])
{
int i = 0;
for(int j=0;j<200;j++){
if((scanf("%d", grade+j) == -1) || (grade[j]==-1))
break;
i++;
}
return i;
}

Related

Storing an array in C

Context: I need to write a program that will accept inputs which will be stored into the array. Before storing in to the array, the inputted number must be checked if it already exists in the array or not. If it does not exist, it is stored into the array. If it exists, another input will be asked.
Now, my code will get inputs from the user, but the code will only work for the first input. It won't work for the second until the last input. Any pointers?
This is my code:
#include<stdio.h>
#define size 5
main()
{
int i;
arr[size];
input;
printf("This program will accept ");
printf("unique inputted numbers that will be stored");
printf(" in an array\n");
for(i = 0;i < size;i++)
{
printf("Enter input: ");
scanf("%d",&input);
if (unique(arr,input,i))
arr[i] = input;
else
i--;
//decrement i because ask for input again
}
for(i = 0;i < size;i++)
printf("%d ",arr[i]);
}
int unique(int arr[],int input,int i)
{
int n, z;
n = 0;
z = 1;
while(i > n)
{
if(arr[n] == input)
{
scanf("%d",&n);
z = 0;
break;
}
else
n=1;
break;
}
return z;
}
Your code is wrong at multiple levels:
The logic in the unique function is wrong.
Doing the scanf in the unique function is extremely bad design. The only thing unique should do is return 0 if input is already in the array.
You have used implicit variable declarations here: arr[size]; input;, it should be int arr[size]; int input;.
You should use descriptive variable names which makes your code easier to understand.
This is a working example (explanations in comments).
#include <stdio.h>
#define SIZE 5 // use capitals for macros (this is a convention)
int unique(int arr[], int value, int arrsize)
{
for (int i = 0; i < arrsize; i++)
{
if (arr[i] == value)
{
return 0; // value found in array
}
}
return 1; // value not found in array
}
void Test(int arr[], int arrsize, int value, int expected)
{
if (unique(arr, arrsize, value) != expected)
printf("Test failed for value %d\n", value);
}
void runtests()
{
int arr[] = { 1,2,3 };
Test(arr, 4, sizeof(arr) / sizeof(*arr), 1);
Test(arr, 1, sizeof(arr) / sizeof(*arr), 0);
Test(arr, 3, sizeof(arr) / sizeof(*arr), 0);
}
#define size 5
int main()
{
int i;
int arr[size]; // declare int variable
int input; // declare int variable
printf("This program will accept unique inputted numbers that will be stored in an array\n");
for (i = 0; i < size; i++)
{
printf("Enter input %d: ", i + 1);
scanf("%d", &input);
if (unique(arr, input, i)) // value already in the array?
arr[i] = input; // no => put it there
else
{ // yes => ask again
printf(" >> %d is already in the array\n");
i--;
}
}
for (i = 0; i < size; i++)
printf("%d ", arr[i]);
}
There are two more functions Test and runtests in this code. They are not called by this code, but they can be very useful for debugging. As an exercise try to understand why they can be useful during the debug phase of your code.
You're close, but overcomplicating it slightly.
Let's take a step back and think about this at a high level. You want to store unique inputs in the array, up to the size of the array. In pseudocode:
while array not full
prompt for and read next input
if input not already in array
store input
else
write a message
end if
end while
What's really key is that you only need one input statement - your unique function should only check for the presence of the input value in the array and return true or false. It shouldn't do any input of its own.
So your main loop is more like
while ( i < size )
{
fputs( "Gimme a number: ", stdout );
/**
* Break out of the loop if there's an error
* on input.
*/
if ( scanf( "%d", &input ) != 1 )
break;
if ( unique( arr, i, input ) )
arr[i++] = input;
else
printf( "%d already exists in the array, try again.\n", input );
}
All your unique function needs to do is cycle through the elements of the array. By calling unique with i instead of size it will only check array elements that have been written to so far and not bother with unassigned elements. This way you don't have to make sure that all of the array elements have been initialized to some known, out-of-band value that's guaranteed to compare unequal to any valid input.
You'll need to compile against C99 or later and include stdbool.h to use the bool type and the true and false constants.
#include <stdbool.h>
...
bool unique( int *arr, size_t size, int input )
{
bool result = true;
for( size_t i = 0; i < size && result; i++ )
if ( arr[i] == input )
result = false;
return result;
}
If you want to get really terse, you could directly assign the result of the Boolean expression to result:
for ( size_t i = 0; i < size && result; i++ )
result = (arr[i] == input);
but people will hit you. It's perfectly valid code, but a little eye-stabby, and most programmers aren't used to seeing Boolean expressions outside of an if, for, while, or switch statement control expression.
Finally, some suggestions:
Fix your formatting. The compiler doesn't care, but it makes it easier for other people to understand what you're trying to do and to spot mistakes.
The presence of main() in your code suggests you're using C89 or K&R C. C99 did away with implicit int declarations. You really should define main as either int main( void ) or int main( int argc, char **argv ). Furthermore, you should move to a compiler that supports later versions of C (C11 or C18).

new to c problem with simple game problem with function

im new to c i try to make a little and very simple game of hangedman and i dont know why doesent work get error in gcc "expected declaration or statement at the end of input"
im new to c and ii try very hard to learn it.
im missing something? my function is not right? some advice to learn alghorytmically thinking?
thanx in advance for the hel you gonna give me
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//function to find letter in string
int findletter(char y)
{
char c;
int i;
char secret[] = "outcast";
i = 0;
scanf("%c", &c);
while (c != secret[i] && i < strlen(secret))
i++;
if(c == secret[i])
return (1);
else
return (0);
}
//confirmation letter
int guessed(char a)
{
int z;
char guess [6] = {0};
z = 0;
while(findletter(guess[z]) != 1 && findletter(guess[z]) < 6)
{
z++;
if(findletter(guess[z]) == 1)
return 1;
else
return 0;
//word guessed
int tryguess(char v)
{
int x;
x = 0;
while(findletter(guess[x]) == 0)
{
x++;
if(findletter(guess[x] == 1))
return 1;
else
return 0;
}
}
int main()
{
char secret[] = "outcast";
char letter;
int lives;
char guess [6] = {0};
int i;
lives = 10;
i = 0;
printf("welcome to the hanged man\n");
while(i < 6)
{
if((findletter(secret[i] == 1)))
printf("%c", secret[i]);
else
printf("*\n");
i++;
}
return 0;
}
Correction to your code...
int guessed(char a)
{
int z;
char guess [6] = {0};
z = 0;
while(findletter(guess[z]) != 1 && findletter(guess[z]) < 6)
{
z++;
if(findletter(guess[z]) == 1)
return 1;
else
return 0;
} // you forgot closing while loop here
} // function closing parenthesis
//word guessed
Advice:
I don't know how much you had practice and how much you had learned yet..but on observing your mistake above I would like to suggest that whenever you create function or loop always write its prototype first, let's say you want to create a function for adding two numbers..
STEP 1: write prototype
int add(int x, int y)
{
//then do your stuff here...
return 0;
}
This will eliminate you chances of making error of parentheses...
There are a lot of issues with this program, from both a syntax standpoint and a logical one.
General issues include:
Function guessed and its while loop are not closed (missing }).
There is a lot of unused code (functions and variables).
The line if((findletter(secret[i] == 1))) compares the character value of secret[i] with 1 and passes that result to findletter. This doesn't matter though since you don't use this argument, and take user input within the function.
You have hardcoded strings and lengths, which makes your program less dynamic and harder to change in the future.
Using while loops as guards (in the unused functions tryguess and guessed), that are always exited on the first iteration.
findletter simply checks if secret contains the character c, returning on the first occurrence.
It could be more clearly expressed as:
int findletter(char unused) {
char secret[] = "secret",
c;
scanf(" %c", &c);
for (size_t i = 0; i < strlen(secret); i++)
if (secret[i] == c)
return 1;
return 0;
}
With that said, findletter would be better if you passed both the secret and c as arguments, so that you can use it more generically, and decouple user input from the function itself.
(Or you could simply use the standard library function strchr which achieves a very similar goal.)
The pattern of
if (a == b)
return 1;
else
return 0;
can simply be reduced to
return a == b;
Aside from the issues above, the structure of your program doesn't make much sense. If our program worked, you'd basically be asking the player to guess a word of unknown length, one character of the word at a time. They can also simply guess any letter to display the current one. One could 'solve' the entire word "secret" by simply inputting 's' repeatedly.
The structure of a very basic hangman program is:
Select the word to be guessed. Select number of lives.
Create a blanked version of word to track progress. Display this blanked version, which indicates the length to the player.
Ask the player to guess a letter. Skip those already guessed.
Update all positions in the blanked version where letter appears in the word.
Decrement lives on miss, end game if out of lives.
Check if the amount of characters changed in the blank version matches the length of word.
Win condition, or return to step 3.
There are many different ways to achieve this, and there are likely thousands of examples online.
Here is a rough program that is about as simple as it gets. This showcases the usual structure and flow of a game of hangman.
#include <stdio.h>
#include <string.h>
size_t update_all(char *to, const char *from, size_t len, char g) {
size_t changed = 0;
for (size_t i = 0; i < len; i++)
if (from[i] == g) {
to[i] = g;
changed++;
}
return changed;
}
void play_hangman(const char *word, unsigned lives) {
size_t word_length = strlen(word),
blanked_length = 0;
char blanked[word_length + 1],
guess = '\0';
for (size_t i = 0; i < word_length; i++)
blanked[i] = '*';
blanked[word_length] = '\0';
while (lives) {
printf("The word: [%s]\n"
"(Lives = %u) Enter a guess: ",
blanked,
lives);
scanf(" %c", &guess);
if (strchr(blanked, guess)) {
printf("[%c]: Already guessed!\n", guess);
continue;
}
size_t found = update_all(blanked, word, word_length, guess);
blanked_length += found;
if (!found) {
printf("[%c]: NOT FOUND!\n", guess);
lives--;
} else
printf("[%c]: FOUND!\n", guess);
if (!lives)
puts("Out of lives! You lose!");
else if (blanked_length == word_length) {
printf("You win! Word is [%s].\n", word);
return;
}
}
}
int main(void) {
play_hangman("secret", 10);
}
Note that this program is far from perfect, as it doesn't fully keep track of guessed letters, so the player can guess the same wrong letter multiple times, and lose a life every time. To fix this, we would need even more state, collecting each guess the player makes, and use that data instead of the naive if (strchr(blanked, guess)).
It also makes use of the '*' character as a sentinel value, which would cause confusion if our word contained '*'. To fix this, we could use an array of boolean values indicating the correctly guessed letters in the word thus far, and use this to print our word character-by-character. Or we could restrict character inputs with functions like isalpha.
This program simply serves as an example that for a proper approximation of the typical "Hangman" you need to handle more game state than you have.
(Error handling omitted for brevity throughout this answer.)

How to dynamically take user input and store it into an integer array

I have an integer array like int a[50];. Now I want to store values entered by the user in the integer array as integers.
The problem is that I don't know the number of elements the user is going to input and hence I am unable to traverse the entire array.
So is there any method for the user to input the values dynamically and store it in the integer array and display it.
For this take a input from user for number of element to have in an array. Then malloc that memory and store the inputs in the array.
You can use realloc and make a specific input as end of the input
int readinput(int *value)
{
int status;
//function returns 0 on conversion -1 if exit keywoard entered
return status;
}
int value, *table = NULL,size = 0;
while (!readinput(&value))
{
table = realloc(table, (size++ + 1) * sizeof(int));
if (table == NULL)
{
break;
}
table[size] = value;
}
example converting function you can find here:
How to get Integer and float input without `scanf()` in c? in my answer
This code should work well, you can change BUFFER_SIZE to whatever you want, after these steps array will realloc to arr size + BUFFER_SIZE.
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 50
int main(void)
{
int * userInputBuffer = malloc(sizeof(int) * BUFFER_SIZE);
int userInput;
int counter = 0;
int reallocCounter = 1;
while ((scanf(" %d", &userInput)) == 1)
{
if ((counter % BUFFER_SIZE) == 0)
{
userInputBuffer = realloc(userInputBuffer, (reallocCounter++ + 1) * BUFFER_SIZE * sizeof(int));
}
userInputBuffer[counter++] = userInput;
}
for (int i = 0; i < counter; i++)
{
printf("User input #%d: %d\n", i + 1, userInputBuffer[i]);
}
free(userInputBuffer);
return 0;
}
The following solution uses the scanf() function with %d as format specifier. The while loop checks the return value so that it can detect if the conversion was successful. If anything other than a valid number is inputted the loop will break. A valid number is also beginning with space but not with any other characters.
The memory is allocated with malloc() and will be reallocated with realloc() each time the user entered a number. Note that there is no error checking about the reallocation this should be done with a temporary pointer like here.
Further this code will reallocate for every single number. You could also reallocate in bigger steps to avoid reallocation on every input. But this only matters if there is much data. In this case the speed improvement wouldn't matter.
After the memory is no longer needed you have to use free().
The user can type:
1<Enter>
2<Enter>
3<Enter>
any characters<Enter>
and will get:
Numbers entered:
1 2 3
as output.
Code:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
size_t idx;
int number;
size_t count = 0;
int* numberArr = malloc(sizeof(*numberArr));
printf("Enter each number separated by <Enter>,\n"
"to abort type any other character that isn't a number!\n");
while (scanf("%d", &number) == 1)
{
numberArr = realloc(numberArr, (count + 1) * sizeof(*numberArr));
numberArr[count] = number;
count++;
}
printf("\nNumbers entered:\n");
for (idx = 0; idx < count; idx++)
{
printf("%d ", numberArr[idx]);
}
printf("\n");
free(numberArr);
return 0;
}

scanf confusion with type error

I just make a program to guess some random pairs in an array,if guess right, delete this pair.
I met a problem that I can only type integer number.Everytime I tried to type like * ,the program will crash. I use a condition like:
if (scanf("%d",&temp)==1)
to try to fix my problem, but it really does'nt work.
here is my code and please give me some help:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int r[4]; //random
int s[8]; //store
char c[8]; //cover
int g[8]; //guess
int i;
int round=0;
int left = 4;
int point = 0;
int clear_index[2];
int temp;
// generate random number
for (i=0;i<4;i++)
{
r[i] = (rand()%10)+1;
s[i] = r[i];
s[i+4] = r[i];
}
// show the default number
printf("[show] ");
for (i=0;i<8;i++)
{
printf("%d ",s[i]);
c[i] = '*';
}
printf("\n");
while(left>0)
{
// print left
printf("[cover] ");
for (i=0;i<8;i++)
printf("%c ",c[i]);
printf("\n");
//guess
printf("[guess] ");
for(i=0;i<8;i++)
{
if (scanf("%d",&temp)==1)
g[i] = temp;
if (g[i] == s[i])
{
printf("v\n");
clear_index[point] = i;
point++;
}
}
if (point == 2)
{
for (i=0;i<2;i++)
c[clear_index[i]]=' ';
left-=1;
point = 0;
}
round+=1;
//left-=1;
}
printf("you won in %d round",round);
}
You get the segmentation fault, because, in case, you did not enter an integer, scanf will not return 1, and then, using g[i] will invoke undefined behavior.
FWIW, g is a local automatic array variable, and unless initialized explicitly, will have indeterminate value. Attempt to read the value will invoke the UB.
Solution:
Always initialize the local variables.
In case scanf() fails, you need to eat up the invalid input using some loop like while (getchar != '\n'); before you proceed to take the next input.
You are reading a number but the user can place a digit. To prevent this you can use the function atoi() from the library stdlib.h. It converts a string to a integer, if the integer is just number digits, it'll convert it to a integer. If it is a character it will return 0. So you just need to prevent the occurrence of a 0 after the atoi() function is called.

pulling values from pointers in a loop

getLine is a function that gets a line, I'm trying to combine lines together outside the getLine function. When ever I try doing this in a loop it messes up the output. I bet it has to do with the pointers, but I have spend many hours trying to figure it out.
int num;
int matrix[370];
i=1;
j=0;
while(*(point=getLine(infile)) != -2){
n[j]=*point;
if(n[0] != n[j]){
printf("matrix dim error 1");
break;
}
while (i<=n[j]){
matrix[i+(3*j)] = *(point+(i+(3*j)));
i++;
printf("%d", matrix[i+(3*j)]);
}
printf("%d %d %d\n", matrix[1],matrix[2],matrix[3]);
j++;
}
fclose( infile );
}
int *getLine(FILE *infile){
int l=0;
int line[7];
int i=1;
int *point;
while ((l=getNum(infile)) != -1){
if(l==EOF){
line[0]=EOF;
point = &line[0];
return(point);
}
line[i]=l;
i++;
}
if(i==1){
line[0]=-2;
point = &line[0];
return(point);
}
line[0]=(i-1); //stores the length of the line in first space
printf("%d %d %d\n",line[1],line[2],line[3]);
point = &line[0];
printf("%d\n",*point);
return(point);
}
int getNum(FILE *infile) {
int c=0;
int value=0;
while ((c=fgetc(infile)) != '\n') {
if(c==EOF){
return(EOF);
}
if((c==32)||(c==13)){
if(value != 0){ //Making sure a number has been gotten
//printf("%d\n\n", value);
return(value);
}
//otherwise keep getting characters
}
else if ((c<=47)||(c>=58)){
printf("incorrect number input %d\n", c);
exit(1);
}
else {
value = (10*value) + (c - '0');
}
}
return(-1);//flags that the end of line has been hit
}
There is one problem:
int *getLine(FILE *infile){
int line[7];
int *point;
point = &line[0];
return(point);
}
You return a pointer to a local variable. It becomes invalid when you return from the function. You could allocate it instead on the heap, or let the caller provide it as an argument.
Instead of
while (i<=n[j]){
didn't you mean
while (i<=n[j][0]){
More Edit: That's actually ok, i overlook the * in the assignment.
Edit: Some more things:
there is no check that the range of int is not exceeded in getNum
there is no check in getLine that more than 7 values are read (which would blow int line[7]
the matrix calculation in my opinion assumes that there are 3 values read, getLine can deliver up to 7
matrix[i+(3*j)] = *(point+(i+(3*j))); ?? point is only 7 int big!!! so for the second value it will read beyond defined data. Shouldn't it read matrix[i+(3*j)] = point[i];
hth
Mario
BTW: I strongly recommend:
resort to std-lib functions
better naming (i and j in the same source are strongly discouraged)

Resources