I learned in the text book, that there are only a few ways you can initialize an array.
Method one:
int ary[5] = {1,2,3,4,5};
Method two:
int ary[] = {1,2,3,4,5};
But what if I want to input user defined values into the array. Would this code be ok? Can anyone teach me a better way to do this?
#include<stdio.h>
#include<conio.h>
int main()
{
int i, n;
printf("Enter array parameter: \n");
scanf("%d",&n);
int a[n];
int b[n];
for(i=0;i<n;i++)
{
printf("Enter value for array a[%d]: \n",i+1);
scanf("%d",&a[i]);
}
n -= 1;
for(i=0;i<=n;i++)
{
b[i]=a[n-i];
}
printf("Value of array b[] is: \n");
for(i=0;i<=n;i++)
{
printf("%d ",b[i]);
}
for(i=0;i<=n;i++)
{
printf("\narray b[%d] = %d ",i,b[i]);
}
getch();
}
int ary[5] {1,2,3,4,5};
This is not a valid array initialization. It should be
int ary[5] = {1,2,3,4,5};
Note the equal sign.
Other wise your array initialization is valid for C99 and above. Plain c would not allow the use of a variable to initialize the array size.
You have a large number of issue, Undefined Behavior being the most critical:
n -= 1;
for(i=0;i<=n;i++)
{
b[i]=a[n-i];
}
When i == n, you index one beyond the end of your b[] array. All arrays in C are zero-indexed, so your loop limits are 0 <= i < n. By using i<=n you loop one-too-many times.
You fail to check the return of any user-input. Try entering '"one"', or accidentally hitting 'r' instead of 4 and see what happens. You must check the return for every user-input and handle the error. What happens if the user enters 1, 2, 'r', 5? You must also empty stdin of any extraneous characters or they will bite you again on your next input.
Don't use conio.h. That makes your code 100% non-portable. You can use the functions in stdio.h for your needs.
That said, when you need to do repetitive tasks like taking integer input, write a short function to do it. You can write one that takes a pointer to the integer to fill, and a pointer to the prompt to display and returns 0 on success or -1 if the user cancels input by generating a manual EOF with Ctrl+d on Linux or Ctrl+z on windows. You can add a helper-function to empty stdin, e.g.
void empty_stdin (void)
{
int c = getchar();
while (c != '\n' && c != EOF)
c = getchar();
}
int getint (int *n, const char *prompt)
{
int rtn;
for (;;) {
fputs (prompt, stdout);
rtn = scanf ("%d", n);
if (rtn == EOF) {
fputs (" (user canceled input)\n", stderr);
return -1;
}
else if (rtn == 0) {
fputs (" error: invalid integer input.\n", stderr);
empty_stdin();
}
else
break;
}
empty_stdin();
return 0;
}
The rest of your program to read an array in a[] and reverse it in b[] is simply:
int main (void) {
int i = 0, n;
if (getint (&n, "Enter array parameter: ") == -1)
return 0;
int a[n], b[n];
for (i = 0; i < n; i++) {
char buf[128];
sprintf (buf, "enter value for a[%d]: ", i+1);
if (getint (&a[i], buf) == -1)
return 0;
}
for (i = 0; i < n; i++)
b[i] = a[n - 1 - i];
puts ("\nvalue of array b[]:");
for (i = 0; i < n; i++)
printf (" %d", b[i]);
putchar ('\n');
#if defined (_WIN32) || defined (_WIN64)
getchar(); /* hold terminal open on windows - type any char, hit return */
#endif
}
Example Use/Output
All valid inputs:
$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: 2
enter value for a[5]: 1
value of array b[]:
1 2 3 4 5
Errors in input:
$ ./bin/getarray
Enter array parameter: foo
error: invalid integer input.
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: four
error: invalid integer input.
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: I'm getting tired of this game...
error: invalid integer input.
enter value for a[4]: 2
enter value for a[5]: 1
value of array b[]:
1 2 3 4 5
User cancels input:
$ ./bin/getarray
Enter array parameter: 5
enter value for a[1]: 5
enter value for a[2]: 4
enter value for a[3]: 3
enter value for a[4]: (user canceled input)
Look things over and let me know if you have further questions.
As someone noted, the first way does not work in C. It is valid C++ though.
The second way int ary[] = {1,2,3,4,5}; works, the array ary is initialized with 5 items at compile time (before you even run the program). The memory is allocated on the stack.
You could also do it like this int ary[6] = {1,2,3,4,5};, where you specify what length you want the array to be. You can then access ary[5] and change it to whatever value you want (by default it is 0).
NOTE: ary[6] is out of bounds, since the array's elements go from 0 to 5.
In your code, you make use of something called Variable Length Arrays (VLAs), and as noted by Wikipedia, they are allocated with automatic storage duration on the stack. This means that when the function where you declared them ends, their life duration also ends (they are local to the function scope you declare them in). To understand why this is important, consider this piece of code:
int *func(int n) {
int v[n]; // variable length array
v[0] = 1;
v[1] = 2;
v[2] = 3;
return v; // this will not work, variable length arrays will be destroyed
// when the function they belong to goes out of scope
}
int main() {
int *v;
v = func(3); // when you will try to access the memory in v, it will be undefined
// behaviour (can seg fault, the memory is not yours anymore)
// print values in v
return 0;
}
To fix this issue, you need to use malloc defined in stdlib.h.
int *func(int n) {
int *v = malloc(sizeof(int) * n); // allocate memory for n elements
v[0] = 1;
v[1] = 2;
v[2] = 3;
return v; // this will now work
}
int main() {
int *v;
v = func(3); // this will work
// print values in v
free(v);
return 0;
}
The reason this works is because memory allocated using malloc is allocated on the heap, meaning it survives the whole duration of the program unless you deallocate it yourself (this means that you need to free the memory at the end using the function free).
Array initializing in C:
int ary[5] {1,2,3,4,5};
This is invalid syntax in c (this is valid in c++).
there is 3 ways to initialize c arrays:
with the curly brackets {} like you did (int ary[] = {1,2,3,4,5};)
iterating on the array elements one by one in for loop and initialize each one of them.
via : memset(void *str, int c, size_t n);, for padding the whole array in the same value. e.g. if i want to initialize the array with 0x0, then, memset call will lokks like: memset(arr, 0x0, sizeof(arr));
Regarding the you code:
for each scanf(..) in the code you have to check and validate scanf("%d",&n);, return/errors and user input in n before make any progress in your code. How you check? see later.
In you situation, it's good to limit the user input n and validating that n in defined range (N_min <= n <= N_max), rather than causing to huge array allocating on the stack in case n was set to maximum value by user!
if(scanf("%d",&n) == EOF){
/*errors ocuured*/
f_invoke_error_handling_rotuine();
}
In f_invoke_error_handling_rotuine(..), you can do what ever your code needs to perform, maybe abort() with error message, maybe setting default values to n...etc.
see reference for memset and scanf in man7.org:
scanf, memset
"Would this code be ok? Can anyone teach me a better way to do this?"
This code is okay from a syntactical perspective (you corrected the wrong initialization), but not portable since you use variable length arrays (VLAs) which might not supported by any implementation (They are provided my compiler extensions) and were only fully compliant to the C99 standard.
A better way to do this, is to use malloc() instead and allocate the memory for the array on the heap.
This also has the advantage that you can resize the array if you want to (make it larger f.e.) and free() the memory for the array when no longer needed.
Related stuff:
Is it a good idea to use C99 VLA compared to malloc/free?
Is there any overhead for using variable-length arrays?
When to use variable length array in C, but when a dynamic allocation?
int i, n;
printf("Enter amount of array elements: \n");
if (scanf("%d",&n) != 1)
{
fputs("Error at input!", stderr);
return EXIT_FAILURE;
}
int* a = malloc ( sizeof(*a) * n );
if (!a)
{
fputs("Error at allocation for a!", stderr);
return EXIT_FAILURE;
}
int* b = malloc ( sizeof(*b) * n );
if (!b)
{
fputs("Error at allocation for b!", stderr);
return EXIT_FAILURE;
}
for (i = 0; i < n; i++)
{
printf("Enter value for array a[%d]: \n", i);
if (scanf("%d", &a[i]) != 1)
{
fprintf(stderr, "Error at input for a[%d]!", i);
return EXIT_FAILURE;
}
}
...
free(a);
free(b);
Related
I'm new to coding and started learning pointers and i'm stuck at a question.
How do I take the array input and print the same array using pointers?
Also it'll be great if you can guide me how to pass variables from function to main().
thanks
#include <stdio.h>
#include <stdlib.h>
int* record_array (int *size_ptr);
int* print_array (int *array_ptr [], int *size_ptr);
int* record_array (int *size_ptr)
{
int *array_ptr = (int*) malloc(*size_ptr*sizeof(int));
for (int index = 0;index < *size_ptr;++index)
{
printf("Enter element at index %d", index);
scanf("%d", &array_ptr[index]);
}
return array_ptr;
}
int* print_array (int *array_ptr [], int *size_ptr)
{
for (int index = 0;index < *size_ptr;++index)
{
printf("%d ",array_ptr[index]);
}
int *pass = array_ptr;
return pass;
}
int main()
{
int size = 0;
printf("How many elements do you want?");
scanf("%d", &size);
record_array(&size);
print_array(&array_ptr,&size);
free(pass);
return 0;
}
You are close, but you have used int *array_ptr [] in int* print_array (int *array_ptr [], int *size_ptr) incorrectly. You further have no pointer in main() to hold the address returned by int *record_array (int *size_ptr) to use in main() and free when it is no longer needed. print_array simply prints the array and returns nothing (it shouldn't return anything) so it should just be type void, e.g. void print_array (int *array_ptr, int *size_ptr)
On access, (subject to 4-exceptions not relevant here), an array is converted to a pointer to the first element C11 Standard - 6.3.2.1 Other Operands - Lvalues, arrays, and function designators(p3). When you want to pass an array, you simply pass the array as a parameter and it is converted to a pointer automatically.
Also note, there is NO array in the entirety of your code. You declare a pointer and then allocate a block of memory to hold your integer values and you assign the starting address for that block to your pointer. (e.g. the pointer holds the starting address for the allocated block as its value, it "points" to that block of memory)
For starters, in main(), you need a pointer to hold the address returned by record_array, e.g.
int size = 0;
int *array = NULL; /* you need a pointer to hold the address of your array */
In record_array (and for every allocation), you must check the return of malloc() to validate whether it succeeded or failed, e.g.
int *record_array (int *size_ptr)
{
int *array_ptr = malloc (*size_ptr * sizeof *array_ptr);
if (!array_ptr) { /* validate EVERY allocation */
perror ("malloc-array_ptr");
return NULL;
}
...
(note: the use of the dereferenced pointer to set the type-size for the allocation. Using the dereference pointer -- you will never get it wrong. In C, there is no need to cast the return of malloc, it is unnecessary. See: Do I cast the result of malloc?)
With input, you must validate every input, e.g. in record_array() that would be:
for (int index = 0; index < *size_ptr; index++)
{
printf ("Enter element at index %d: ", index);
if (scanf ("%d", &array_ptr[index]) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return NULL;
}
}
Expanding a bit on the validations, every time you do something in your code that can fail (like take user input or allocation memory), it is imperative that you validate the return before using the results in your code. Above, if you simply do scanf ("%d", &array_ptr[index]) a simply slip and tapping 'r' instead of '5' would go unnoticed but lead to invalid results in your code (and perhaps Undefined Behavior if it occurred on the first character)
So to prevent using invalid data, you check the return of the function you are using. With scanf it returns the number of successful conversions or EOF if failure occurs before the first conversion takes place. So when taking input with scanf you always check that the return matched the number of conversions you specify in your format-string. With "%d" -- one conversion to int will take place. So to validate the input, you use:
if (scanf ("%d", &array_ptr[index]) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return NULL;
}
(which just say if the return from scanf() isn't 1 -- handle the error -- which is to return failure (or NULL) in this case)
Finally in main(), you will validate the return of record_array is not NULL before using the allocated block in print_array(), e.g.
if ((array = record_array (&size))) { /* validate record_array succeeds */
print_array (array, &size); /* print array */
free (array); /* free array */
}
(the comparison is shorthand for: if ((array = record_array (&size)) != NULL) {.... You could have done the assignment separately, e.g. array = record_array (&size); and then if (array != NULL) {... so long as you validate the return :)
Making those corrections (and providing a space in the prompt to separate the prompt and the input) you would have:
#include <stdio.h>
#include <stdlib.h>
int *record_array (int *size_ptr);
void print_array (int *array_ptr, int *size_ptr);
int *record_array (int *size_ptr)
{
int *array_ptr = malloc (*size_ptr * sizeof *array_ptr);
if (!array_ptr) { /* validate EVERY allocation */
perror ("malloc-array_ptr");
return NULL;
}
for (int index = 0; index < *size_ptr; index++)
{
printf ("Enter element at index %d: ", index);
if (scanf ("%d", &array_ptr[index]) != 1) {
fputs ("error: invalid integer input.\n", stderr);
return NULL;
}
}
return array_ptr;
}
void print_array (int *array_ptr, int *size_ptr)
{
for (int index = 0; index < *size_ptr; index++)
printf ("%d ",array_ptr[index]);
putchar ('\n'); /* tidy up with newline */
}
int main()
{
int size = 0;
int *array = NULL; /* you need a pointer to hold the address of your array */
printf("How many elements do you want? ");
if (scanf("%d", &size) != 1) { /* validate EVERY input */
fputs ("error: invalid integer input.\n", stderr);
return 1;
}
if ((array = record_array (&size))) { /* validate record_array succeeds */
print_array (array, &size); /* print array */
free (array); /* free array */
}
}
Example Use/Output
$ ./bin/readarrayfunc
How many elements do you want? 5
Enter element at index 0: 1
Enter element at index 1: 2
Enter element at index 2: 3
Enter element at index 3: 4
Enter element at index 4: 5
1 2 3 4 5
Note also with declarations the '*' goes with the variable, not the type. Why? Readability. Look at:
int* a, b, c;
That certainly does not declare 3-pointers to int, it declares one pointer to int and two integers:
int *a, b, c;
makes that clear.
Look things over and let me know if you have further questions.
I need to create an array of ints of an unknown size and pass them all. My code looks like this:
int FillTable(int a[], int max){
int i;
int x = 0;
int m = 0;
for (i = 0; i < max; i++){
printf("Fill the table with integers: ");
scanf("%d", &m);
if (m != "" && m != NULL){
a[i] = m;
}else if (m != "" && m == NULL){
a[i] = 0;
}else{
break;
}
}
printf("\n");
return 0;
}
I know you can pass multiple ints separated by spaces with something like:
scanf("%d %d %d", &var1, &var2, &var3);
But I don't know how to pass a number of integers that I don't know how many will be there. Could I create a string with a bunch of %d and just repeat that for max times? I don't know, but right now, I just ask for ints until the array is full, and I need to be able to have the array be smaller than max if the user doesn't enter in enough values. Does anyone have any ideas as to how I would go about scanning for an unknown number of integers?
Does anyone have any ideas as to how I would go about scanning for an unknown number of integers?
This calls for Dynamic memory allocation!
One way of going with scanning unknown number of integers is, firstly allocate an integer array with size to hold max number of integers.
How to know whether user has ended his input?
If you are only scanning in positive integers from user at array entries then prompt him to end his input by inputting a negative number
or if you are sure about the range of input entries then break out of loop, when user enters input out of range
Example: (considering user inputs only positive numbers)
//creating a large enough array to store user inputs
int *array = malloc(sizeof(int) * max);
//check if memory was allocated or not
if(array == NULL)
{
printf("memory allocation problem!");
exit(1);
}
//integer to make note of size of array or you can use the sizeof() function instead
int size_of_array = 0;
for (i = 0; i < max; i++)
{
printf("Fill the table with integers: ");
if(scanf("%d", &m) != 1) //check for scanf return value
{
printf("wrong input, try again");
char consume; //to consume the character
scanf("%c", &consume);
i--;
continue;
}
if (m > 0) //if positive number, accept
{
array[i] = m;
size_of_array++;
}
else //else break out of scanning
{
break;
}
}
//do the program.....
//don't for get to free the memory at the end
free(array);
here's a working example: https://ideone.com/BHN4sk
You are trying to do something that is not necessary. To predict the size of the array and reallocate the appropriate exact size would be computationally more expensive (in terms of cpu time) so that benefit of saving the memory that you already had allocated is not enough.
The size of the array in c is stored somewhere that not necessarily has anything to do with the array itself. So you simply need to know how many of the array elements are interesting for the program and nothing else.
You could have something like
struct Array {
int *data;
size_t size;
size_t count;
};
where size is the total size of the array, count is the number of elements in the array and data are the elements. I use this pattern a lot and it's useful, specially if combined with realloc() as it saves from unecessarilly reallocating memory too many times which is expensive at the cost of using slightly more memory than actually needed.
But systems today have way more memory than can be used (except if you use Android Studio, which can use as much memory as your computer has).
First, m != "" && m != NULL probably does not do what you think it does. You're probably coming from a different language. What (I think) that statement does is compare the value in the integer variable m to the address of the string literal "" and then compare it to NULL (which evaluates to 0).
Second, scanf by default reads until either a space or a newline.
scanf returns a negative number on failure, so your code should look like this:
for (i = 0; i < max; i++){
printf("Fill the table with integers: ");
if(scanf("%d", &m) > 0) {
a[i] = m;
}
else {
break;
}
}
I left out the a[i] = 0 branch because I don't understand what you wanted there.
Also, you never use the variable x - unless there is more code that you left out.
your problem isn't understand for me properly,however i think this will be helped to you
int arraySize = 200; // Or whatever
int *array_ = malloc(arraySize * sizeof(int));
use this and the pass the *array_ as parameter,first defined array size or get array size as a user input,and run a for loop till size of array
You should decide how the user can stop his input (and include this info in your prompt). A quick-and-dirty way would be "enter anything that is not a number". I chose this way of terminating input, because it's easy to implement (hence, quick and dirty):
printf("Fill the table with integers; terminate with 'x':\n");
for (i = 0; i < max; i++)
{
int result = scanf("%d", &a[i]);
if (result != 1)
break;
}
Note:
The prompt tries to be user-friendly
The scanf function puts the number straight into the array, without using any intermediate variable
The scanf function returns how many numbers it read, which is normally 1; if it's not 1, then the user entered x or anything else
When the code finishes, i holds the number of iterations, which shows how many numbers were read from the user.
Your input function should return the size of the array:
return i; // instead of "return 0"
You might also want to clean the stdin buffer - discard anything that the user entered to terminate the array:
while (getchar() != '\n')
{
// do nothing - keep consuming input until end-of-line
}
Im trying to create a program that has 2 options, view and compute. Right now im trying to figure how to turn my array where i will input my values into a function, so i can go in and out several times to store the values. I also want to view to be a function where i can view the values several times.
i've managed to get the computing part to work in my main, now i need to turn it into a function. Secondly how do i create a second function to view it?
My code is a bit mess please bear with me.
#include <stdio.h>
#define LENGTH 10
int enterMeasurements();
int main(void)
{
char input;
int nrMeasurements=0;
int arrayTable[LENGTH] = {0};
//main menu
do
{
char input;
printf("\nMeasurement tool 1.0\n");
printf("V for (View)\n");
printf("E for (Enter Values)\n");
printf("C for (Compute Values)\n");
printf("R for (Reset Values)\n");
printf("Q for (Quit)\n");
printf("\nEnter input: ");
scanf(" %c", &input);
if(input == 'v' || input == 'V')
{
// function to print array values
printf("[ ]\n");
}
else if(input == 'e' || input == 'E')
{
// enter values here
nrMeasurements = enterMeasurements(arrayTable,nrMeasurements); // my function for entering values
}
else if (input == 'c' || input == 'C')
{
// enter function to calc min, max and avg and prints it.
printf("[ min max avg ]\n");
}
else if (input == 'r' || input == 'R')
{
// enter function that erase the entire array.
printf("[ erase array ]\n");
}
}
while (input !='q' && input != 'Q');
return 0;
}
int enterMeasurements()
{
int enterMeasurements(int arrayTable[], int nrMeasurements)
{
int i;
for (i = 0; i < LENGTH; i++)
{
printf("Enter Measurement #%i (or 0): ", i+1);
scanf("%d", &arrayTable[i]);
if (arrayTable[i] == 0 )
break;
}
return i;
}
To help you get started (you should really read a beginners book on the subject) I will show you the printArray function.
First of all the printArray function needs to know the actual array to print. it also needs to know the number of elements in the array. This can be accomplished in two ways: Global variables (which no-one is really recommending) or with function arguments.
You first need to tell the compiler that the function takes arguments:
void printArray(int *array, size_t numElements)
The above line tells the compiler that the printArray function takes two arguments: One which is called array and is a pointer to int (arrays "decays" to pointers to their first element when passed to functions), and one argument that is named numElements and is of type size_t (which is a good type for sizes and number of elements and similar things). The function is declared to return nothing with the void keyword.
The declared arguments can then be used inside the function like any other variables in the scope of the function, and are in fact just like any other local variable defined inside the function. So you can then use them like e.g.
void printArray(int *array, size_t numElements)
{
for (size_t i = 0; i < numElements; ++i)
{
printf("array[%d] = %d\n", i, array[i]);
}
}
To call this function you need to pass the array and the number of elements, much like you pass arguments to any other function like scanf or printf:
printArray(arrayTable, i);
Note that the function doesn't return anything, which means you can't use it in printf, or any other expression that expects a value.
You should of course also make your forward function prototype declaration match the actual function definition.
Alex, continuing from your last comment, to display a menu that will allow you to add values to your array, delete values from your array and view the array (along with the max, min and average of the values), can do something similar to the following. Note: the command line isn't a windowed user interface, so your menu operations are more like a printed receipt of your transactions with it. (you can do nice text windows and stationary menus, but that generally requires an text library, such as ncurses which is well beyond the scope of your question.
As explained in the comment, your basic approach is simply to create a loop that repeats continually. It will display your menu and allow you to enter your selection from a list, e.g.:
======== Program Menu =========
V) View the Array.
I) Insert New Value.
D) Delete Existing Value.
N) Display Minimum Value.
X) Display Maximum Value.
A) Display Average of Values.
S) Display Sum of Values.
Q) Quit.
Selection:
After the user enters the selection, to make the comparison easier, the user's input in converted to lower-case. Also note, that the input is read as a string using fgets (a line-oriented input function) which makes taking user input much easier than having to worry about whether the '\n' remains in the input buffer (stdin) just waiting to cause problems for your next input. (you can use the scanf family of functions, but YOU are the one responsible for accounting for each character entered by the user (and emptying the input buffer).
Reading input with fgets will read up to and including the '\n', so their is no chance of the '\n' being left unread in stdin. Also note that fgets will read a string or characters, where you are only interested in the first. That is easily handled simply by referencing the first character in the buffer. (e.g. if you are reading user-input into a buffer called buf, you can simply use buf[0] to access the first character, or simply *buf for that matter)
After the user input is read, the first character is passed to a switch statement, where each case of the statement is compared against the first character. If the character matches a case, then the actions associated with that case are taken, ending with the break (you can read about fall-through processing if the break is omitted on your own)
As mentioned in the comment, if you simply need to break out of one loop, then break is all you need. However here, your switch statement is inside the loop. A single break will only get you out of the switch but not the outside for loop. To break out of nested loops, use the goto statement. (you could also add more variables and set some type of exit flag, but why? This is what the goto was meant to do. (there are some cases where a flag is equally good as well)
In each case within the switch, you are free to call whatever code is needed to handle that menu selection. You will note we simply call short helper functions from within the switch to print the array, insert values, remove values, etc. You can put all the code in the switch if you like, it just rapidly become unreadable.
Putting that altogether, you can do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
enum { MAXN = 64 }; /* constant - max numbers of vals & chars */
void showmenu ();
void prnarray (int *a, int n);
int addvalue (int *a, int n, int newval);
int delvalue (int *a, int n, int index);
int minvalue (int *a, int n);
int maxvalue (int *a, int n);
int sumvalues (int *a, int n);
int main (void) {
int vals[MAXN] = { 21, 18, 32, 3, 9, 6, 16 }, /* the array */
n = 7;
for (;;) { /* loop until user quits or cancels, e.g. ctrl+d */
showmenu(); /* show the menu */
char buf[MAXN] = "";
fgets (buf, MAXN, stdin); /* read user input */
/* convert to lower-case for comparison of all entries */
switch (tolower (buf[0])) { /* 1st char is entry */
case 'v' : prnarray(vals, n);
break;
case 'i' : printf ("\n enter the new value: ");
if (fgets (buf, MAXN, stdin) &&
isdigit (buf[0])) {
n = addvalue (vals, n, atoi (buf));
}
break;
case 'd' : printf ("\n enter the index to delete: ");
if (fgets (buf, MAXN, stdin) &&
isdigit (buf[0])) {
n = delvalue (vals, n, atoi (buf));
}
break;
case 'n' : printf ("\n Mininum of '%d' values is : %d\n",
n, minvalue (vals, n));
break;
case 'x' : printf ("\n Maxinum of '%d' values is : %d\n",
n, maxvalue (vals, n));
break;
case 'a' : printf ("\n Average of '%d' values is : %.2lf\n",
n, (double)sumvalues (vals, n)/n);
break;
case 's' : printf ("\n Sum of '%d' values is : %d\n",
n, sumvalues (vals, n));
break;
case 'q' : printf (" that's all folks...\n");
goto done;
default : if (!buf[0]) { /* check for manual EOF */
putchar ('\n'); /* tidy up */
goto done;
}
fprintf (stderr, "error: invalid selection.\n");
}
}
done:; /* goto label - breaking 'for' and 'switch' */
return 0;
}
void showmenu ()
{
fprintf(stderr, "\n ======== Program Menu =========\n\n"
" V) View the Array.\n"
" I) Insert New Value.\n"
" D) Delete Existing Value.\n"
" N) Display Minimum Value.\n"
" X) Display Maximum Value.\n"
" A) Display Average of Values.\n"
" S) Display Sum of Values.\n"
"\n"
" Q) Quit.\n"
"\n"
" Selection: ");
}
void prnarray (int *a, int n)
{
int i;
printf ("\n there are '%d' values in the array:\n\n", n);
for (i = 0; i < n; i++)
printf (" array[%2d] : %d\n", i, a[i]);
}
int addvalue (int *a, int n, int newval)
{
if (n == MAXN) {
fprintf (stderr, "error: all '%d' values filled.\n", n);
return n;
}
a[n++] = newval;
return n;
}
int delvalue (int *a, int n, int index)
{
if (index < 0 || index > n - 1) {
fprintf (stderr, "error: index out of range.\n");
return n;
}
int i;
for (i = index + 1; i < n; i++)
a[i-1] = a[i];
a[i] = 0;
return --n;
}
int minvalue (int *a, int n)
{
int i, min = INT_MAX;
for (i = 0; i < n; i++)
if (a[i] < min)
min = a[i];
return min;
}
int maxvalue (int *a, int n)
{
int i, max = INT_MIN;
for (i = 0; i < n; i++)
if (a[i] > max)
max = a[i];
return max;
}
int sumvalues (int *a, int n)
{
int i, sum = 0;
for (i = 0; i < n; i++)
sum += a[i];
return sum;
}
(note: there are always additional validation checks you can add to test whether you have read all the input the user provided, etc.. But given the crux of your question I'll leave that learning to you)
Example Use/Output
$ ./bin/menusimple
======== Program Menu =========
V) View the Array.
I) Insert New Value.
D) Delete Existing Value.
N) Display Minimum Value.
X) Display Maximum Value.
A) Display Average of Values.
S) Display Sum of Values.
Q) Quit.
Selection: v
there are '7' values in the array:
array[ 0] : 21
array[ 1] : 18
array[ 2] : 32
array[ 3] : 3
array[ 4] : 9
array[ 5] : 6
array[ 6] : 16
======== Program Menu =========
V) View the Array.
I) Insert New Value.
D) Delete Existing Value.
N) Display Minimum Value.
X) Display Maximum Value.
A) Display Average of Values.
S) Display Sum of Values.
Q) Quit.
Selection: i
enter the new value: 77
======== Program Menu =========
V) View the Array.
I) Insert New Value.
D) Delete Existing Value.
N) Display Minimum Value.
X) Display Maximum Value.
A) Display Average of Values.
S) Display Sum of Values.
Q) Quit.
Selection: v
there are '8' values in the array:
array[ 0] : 21
array[ 1] : 18
array[ 2] : 32
array[ 3] : 3
array[ 4] : 9
array[ 5] : 6
array[ 6] : 16
array[ 7] : 77
Look things over and let me know if you have any questions. Also, as you are just learning, make sure you are compiling your code with compiler warnings enabled and that you don't consider your code reliable until it compiles without warning. That means you should be compiling with at least the -Wall -Wextra flags set. If you are using gcc and the command line, then it would be:
gcc -Wall -Wextra -O2 -o simplemenu simplemenu.c
To compile the code in simplemenu.c into an executable named simplemenu with the -O2 optimizations applied. If you are really wanting to eliminate all warnings, add -pedantic as well. For codeblock or other IDE, look through the compiler menu options, they all provide a place to input all of the options you would like. Good luck with your code.
Procedural Approach Without Functions & Input With scanf
OK, now that we know how far we need to backup, let's look at rewriting the code in a bare minimum, top-down approach without using functions and taking user input with scanf (which will cause you more grief, especially taking mixed character and numeric input, but it can be done, if you account for the '\n' left in stdin)
First a note about taking input with scanf. When you ask for user input, like with the menu selection, and the user enters V and presses Enter, the input buffer stdin contains "V\n" (the '\n' as the result of pressing Enter). When you then use scanf to read a character (e.g. char sel; scanf ("%c", &sel);) the 'V' is taken from stdin and stored in sel leaving '\n' in stdin. If you then attempt to read another character (e.g. char nextch; scanf ("%c", &nextch);) it will appear that scanf has skipped reading nextch because it never allow you to enter a value. What has actually happened is scanf ("%c", &nextch); has read the '\n' that remained in stdin as your next character and is quite content with the value of 0xa (10 decimal) in nextch.
You must always account for the '\n' when using scanf. You have two options, 1) leave a space before the conversion specifier (e.g. scanf (" %c", &nextch); or 2) use the assignment suppression operator '*' (e.g. scanf ("%c%*c", &nextch);), the second %*c telling scanf to read and discard the following character without adding the conversion to the match count (which is the integer value returned by scanf). Which brings up the most important point of all, always check the return of scanf. (otherwise, you have no clue whether you have an actual value to work with or just garbage) I will leave the reading of man scanf to you for further details on the effect of the space before the conversion specifier, and the assignment suppression operator.
The return for scanf (the match count) is the number of successful conversions performed based on the number of conversion specifiers contained within the format string (e.g. scanf (" %c %d", &somechar, &someint); contains 2 conversion specifiers %c and %d, so the return for scanf after successful conversion of both would be 2. If a matching or conversion failure occurs, the return will be less than 2 and if an error condition is encountered reading from the stream (stdin in this case) EOF is returned (generally a value of -1) All of this, and more, is why scanf is NOT the preferred method for taking user input in C. (that being said, it is what most tutorials, and most teachers, make the poor choice to expose new C programmers to without an understanding of the pitfalls)
With that out of the way, if you work through the example below, you will see that I have simply moved the code from the functions to within the if ... else if ... else framework. (look at the one-to-one relationship from where I call functions from the switch in the first example and the code below) This should also show why breaking the code up into logical functions, improves readability and improves code re-use. Compare the use of the switch statement with the if ... else if ... else daisy chain. Both are fine, but to me, the switch is more easily readable at a glance.
You should make sure you understand both versions as they are both basic entry level approaches to using C. Take your time going through each and if you have questions that you cannot answer by consulting one of the references provided in the tag-wiki link, just ask.
#include <stdio.h>
#include <stdlib.h> /* for atoi */
#include <limits.h> /* for INT_MIN/INT_MAX */
enum { MAXN = 64 }; /* constant - max numbers of vals & chars */
int main (void) {
int vals[MAXN] = { 21, 18, 32, 3, 9, 6, 16 }, /* the array */
n = 7;
for (;;) {
char c;
/* show the menu */
fprintf(stderr, "\n ======== Program Menu =========\n\n"
" V) View the Array.\n"
" I) Insert New Value.\n"
" D) Delete Existing Value.\n"
" N) Display Minimum Value.\n"
" X) Display Maximum Value.\n"
" S) Display Sum of Values.\n"
" A) Display Average of Values.\n"
"\n"
" Q) Quit.\n"
"\n"
" Selection: ");
/* read selection (inside of if is OK), check EOF or quit */
if (scanf (" %c", &c) == EOF || c == 'q' || c == 'Q') {
printf ("\n that's all folks...\n");
break;
}
if (c == 'v' || c == 'V') { /* view array code */
printf ("\n there are '%d' values in the array:\n\n", n);
int i;
for (i = 0; i < n; i++)
printf (" array[%2d] : %d\n", i, vals[i]);
}
else if (c == 'i' || c == 'I') { /* insert value code */
if (n == MAXN) {
fprintf (stderr, "error: all '%d' values filled.\n", n);
continue;
}
int newval = 0;
printf ("\n enter the new value: ");
if (scanf (" %d", &newval) == 1) {
vals[n] = newval;
n++;
}
else
fprintf (stderr, "error: invalid input.\n");
}
else if (c == 'd' || c == 'D') { /* delete value code */
int i, index = 0;
printf ("\n enter the index to delete: ");
if (scanf (" %d", &index) != 1) {
fprintf (stderr, "error: invalid input.\n");
continue;
}
if (index < 0 || index > n - 1) {
fprintf (stderr, "error: index out of range.\n");
continue;
}
for (i = index + 1; i < n; i++)
vals[i-1] = vals[i];
vals[i] = 0;
n--;
}
else if (c == 'n' || c == 'N') { /* display minimum code */
int i, min = INT_MAX;
for (i = 0; i < n; i++)
if (vals[i] < min)
min = vals[i];
printf ("\n Mininum of '%d' values is : %d\n",
n, min);
}
else if (c == 'x' || c == 'X') { /* display maximum code */
int i, max = INT_MIN;
for (i = 0; i < n; i++)
if (vals[i] > max)
max = vals[i];
printf ("\n Maxinum of '%d' values is : %d\n",
n, max);
}
else if (c == 's' || c == 'S') { /* compute sum code */
int i, sum = 0;
for (i = 0; i < n; i++)
sum += vals[i];
printf ("\n Sum of '%d' values is : %d\n",
n, sum);
}
else if (c == 'a' || c == 'A') { /* compute avg code */
int i, sum = 0;
double avg = 0.0;
for (i = 0; i < n; i++)
sum += vals[i];
avg = (double)sum/n;
printf ("\n Average of '%d' values is : %.2lf\n",
n, avg);
}
else /* if not matched, then invalid selection */
fprintf (stderr, "error: invalid selection.\n");
}
return 0;
}
(the operation and output from both program versions will be identical)
I would like to count the number of elements in an integer array(sized, like: array[1000]) after input without counting manually while inputting(using scanf() which is = number of arguments passed to scanf).Though int arrays are not null terminated as well as scanf() cannot be used like getchar() or gets() and no availale function like strlen() for int arrays,is it possible to write a C program to prompt the user to input as many numbers as he wishes and the program will count them(total arguments passed to scanf()) and print the maximum using arrays or pointers?
Without having a termination value, you will have to count the inputs as they are made. You could do this by defining a struct to hold the array. Your program does not know how many integers you will enter, and this code allocates more memory when the array is full, keeping track of the array size and elements used.
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_STEP 10 // increment in array size
typedef struct {
int maxlen; // capacity of array
int length; // elements used
int *array; // the array pointer
} istruct;
int main(void) {
istruct intarr = {0}; // empty array
int i;
printf ("Enter some integers:\n");
while (scanf("%d", &i) == 1) {
if (intarr.length >= intarr.maxlen) {
intarr.maxlen += ARRAY_STEP; // increase array size
intarr.array = realloc(intarr.array, intarr.maxlen * sizeof(int));
if (intarr.array == NULL) {
printf("Memory allocation error\n");
exit (1);
}
}
intarr.array[intarr.length++] = i;
}
printf ("You entered:\n");
for (i=0; i<intarr.length; i++)
printf ("%-10d", intarr.array[i]);
printf ("\n");
if (intarr.array)
free(intarr.array);
return 0;
}
strlen() iterates on the character array until the C string termination character (ASCII \0) is encountered. So it is COUNTING the elements. If you want to do that for an int array I guess you could also have a reserved 'terminator' value for your array, make room for it (allocate one more int in your array for the terminator) and implement your own int_array_len() similar to strlen. However, in your case counting the elements while inputting them seems like a much better way to go.
Smart vertion:
#include <stdio.h>
int main()
{
double a[100000],mx=0;
int i,j,c=0;
printf("Enter as many numbers as you wish . Press Ctrl+D or any character to stop inputting :\n");
/*for(i=0;i<100000;i++)
a[i]=0;*/
for(i=0;i<100000;i++)
{
if((scanf("%lf",&a[i]))==1)
c++;
//else break;
}
for(j=0;j<c;j++)
{
if(a[j]>mx) mx=a[j];
}
printf("You have inserted %d values and the maximum is:%g",c,mx);
return 0;
}
It's pretty simple.
just declare of your desired "initial size". And keep checking if input is a valid integer or not.
if((scanf("%d",&a[i]))==1) this would be true if and only if the input is a valid integer. hence the moment the input is not an int, it exits the loop. You can count the number of input values within the same loop and also the max values.
Here is the code:
#include <stdio.h>
#include<limits.h>
int main()
{
int a[100],max = INT_MIN;
int i,j,count=0;
printf("Start Entering the integers... Give any non-integer input to stop:\n");
for(i=0;i<100;i++)
{
if((scanf("%d",&a[i]))==1) {
count++;
if(a[i]>max) {
max = a[i];
}
}
else
break;
}
printf("number of input values: %d;\nThe maximum input value: %d",count,max);
return 0;
}
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]