Why for loop terminates after running only 4 times? - c

I want that array (marks) size increases by 1 with each input of user:
#include <stdio.h>
main() {
int size=1;
int marks[size];
int i;
printf("Enter marks\n");
for(i=0;i<size;i++) {
scanf("%d",&marks[i]);
size++;
}
}

You can't increase the size of your array dynamically. But if you know how many scores will be entered, then you can set size to that value and then accept values until that size is reached.
#include <stdio.h>
int main()
{
int size = 10;
int marks[size];
int i;
printf("Enter marks\n");
for(i = 0; i < size; i++)
{
scanf("%d",&marks[i]);
}
}
Resizing dynamically will increase the complexity of your program significantly, but if that's exactly what you're trying to do, check out R Sahu's answer here or this answer: increasing array size dynamically in c.

Because you have statically declared marks array to size 1. Since you are incrementing size in loop will lead to undefined behavior. Better approach would be allocate marks dynamically.
Consider below example for reference.
#include <stdio.h>
#include<stdlib.h>
void main() {
int size=0;
int *marks = NULL;
int i;
printf("Enter number of marks\n");
scanf ("%d",&size);
marks = (int *) malloc(size*sizeof(int));
printf("Enter marks\n");
for(i=0;i<size;i++)
{
scanf("%d",&marks[i]);
}
}

Your code assumes an increase in size will increase the size of the native array. That isn't how arrays work in C.
Native arrays in C are fixed-length after their definition. If you want to dynamically grow a sequence of things, then you need to manage a dynamic sequence, doing it inner-loop as valid data is received.
Code
The following prompts (or lack thereof) the user in the same fashion your code apparently desired. However, a loop termination condition has been added (a mark entry of -1 will terminate the loop, as will any invalid non-convertible input).
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *marks = NULL, mark = 0;
int size = 0;
printf("Enter marks\n");
while (scanf("%d", &mark) == 1 && mark != -1)
{
// expand marks
void *tmp = realloc(marks, (size+1) * sizeof *marks);
if (tmp == NULL)
{
perror("Failed to expand marks array");
exit(EXIT_FAILURE);
}
marks = tmp;
marks[size++] = mark;
}
// TODO: use marks[0] through marks[size-1] here
for (int i=0; i<size; ++i)
printf("%d ", marks[i]);
fputc('\n', stdout);
// then free marks
free(marks);
return EXIT_SUCCESS;
}
Sample Input
1 2 3 4
5 6
7 8 9
10 -1
Output
1 2 3 4 5 6 7 8 9 10
Notes: There are more efficient geometric growth algorithms that considerably reduce the number of realloc calls, For example, doubling the prior sequence size with each realloc and tracking both size and capacity would reduce your number of allocations from n to log(n). However, for the basic understanding of inline sequence growth, this example should suffice.

I want that array (marks) size increases by 1 with each input of user.
That's not how arrays work in C.
To get that functionality, you'll have to use dynamically allocated memory using malloc and realloc.
Also, your code has a logic flaw. If you look at the variables that control the loop, you have:
int size=1;
int i;
for(i=0;i<size;i++) { // i will never catch up to size before size overflows
size++;
}
For your needs, you can use a variable length array (VLA) or use malloc only once.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int size;
int i;
printf("Enter size\n");
if ( scanf("%d", &size) != 1 )
{
// Problem. Deal with error.
}
// Use a VLA
int marks[size];
// or
// Allocate memory.
// int* marks = malloc(sizeof(*marks)*size);
printf("Enter marks\n");
for ( i = 0; i < size; i++)
{
if ( scanf("%d", &marks[i]) != 1)
{
// Problem. Deal with error.
}
}
// Deallocate the memory. Needed when using malloc
// free(marks);
}

#include <stdio.h>
#include <stdlib.h>
main() {
int size=1;
int *marks = NULL;
int i;
printf("Enter marks\n");
for(i=0;i<size;i++)
{
int *tmpptr = realloc(marks, size * sizeof(*mark));
if(!tmpptr)
{
printf("Memeory allocation error\n");
free(marks);
break;
}
marks = tmpptr;
if(scanf("%d",marks + i) != 1) break;
size++;
}
/* some code */
}

Related

Getting inputs with scanf for an array

Just getting to learn C better and I'm playing with arrays.
I would like to enter my phone number into an array like this:
#include <stdio.h>
int main()
{
int phoneNum[10];
for (int i = 0; i < sizeof(phoneNum); i++) {
printf("Insert digit %d of your phone number: \n", i + 1);
scanf("%d", &phoneNum[i]);
}
return 0;
}
This seems to fail as it keeps asking me for a new digit. So I tried to print the size of the array:
int phoneNum[10];
printf("%lu", sizeof(phoneNum));
which incredibly gives me the result of 40 even though I initialized it to be 10 (?).
I have three questions:
Why is the result 40 and not 10 in sizeof(phoneNum) ?
How can I add elements in an array successfully with scanf in the above manner?
If the above manner is silly, is there a better, more efficient way to do this? For example directly enter 10 digits into an array? I can of course use scanf("%d%d%d...", digit1, digit2, digit3, ...) but I would like a generalized way, using the size of the array (say I don't know it and it's passed from another function)
sizeof(phoneNum) returns 10 * sizeof(int). The sizeof(int) value appears to be 4 for your system.
#include <stdio.h>
int main()
{
int phoneNum[10] = {0};
const size_t size = sizeof(phoneNum) / sizeof(int);
for (int i = 0; i < size; i++) {
printf("Insert digit %d of your phone number: \n", i + 1);
scanf("%d", &phoneNum[i]);
}
for(int i = 0; i < size; ++i)
{
printf("\r\n %i \n", phoneNum[i]);
}
return 0;
}
sizeof(phoneNum) will return number in bytes, not length of array.
after the includes you could make a define like #define SIZE 10 and use SIZE like if it was a constant.
#include <stdio.h>
#define SIZE 10
int main()
{
int phoneNum[SIZE];
for (int i = 0; i < SIZE; i++)
{
//Do Something
}
}
Take into account the fact that strings should end with null terminated character (\0) so the size of the string have that space available.

Having trouble while adding elements to array and print them

I'm trying to create an array which has size depended upon input elements count. After that I want to print it but I'm getting very strange outputs.
int main(void)
{
int input_arr;
int i,size=0;
int arr[size];
while(input_arr!=-1){
printf("enter positive int");
scanf("%d",&input_arr);
arr[size]=input_arr;
printf("%d",arr[size]);
for(i=0;arr[i]!='\0';i++){
printf("%d ",arr[i]);
}
size+=1;
}
return 0;
}
33 3 3 3 3 3 6487488 enter positive int3.
It gives output like this and after a while it stops taking elements. I could not recognize where am I doing wrong.
In C the size of the array is fixed the moment you define it. Increasing the size variable does not increase the array size. Therefore you immediately get a buffer overflow the moment you read the first element. You can instead declare a large array like this:
static const int maxSize = 4096;
int arr[maxSize];
int main(void)
{
int i, size=0;
while(size < maxSize){
printf("enter positive int");
scanf("%d", &arr[size]);
++size;
for(i=0; i < size; i++){
printf("%d ",arr[i]);
}
printf("\n");
}
return 0;
}
Alternatively you can use malloc and realloc to grow the array dynamically.

How do I create an array with undefined length? (In C)

I'm trying to create a program which randomly decides how many cards you have, then randomly allocates a value to each of those cards.
I have managed to randomise the amount of cards, and I know how to randomise their values using an array and a for loop, but the problem is that this method only works when I manually choose a value for the number of elements in the array, but I want the number of elements to be the random amount of cards.
How do I go about this?
Here's my code so far to show what I mean. And yes, I'm aware the code probably could be done better but this is my first C assignment and I'm a complete beginner.
Thanks :)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <windows.h>
int main(void)
{
system("cls"); /* Clears output to start */
srand(time(NULL)); /* Sets seed for random number generator */
int player1_amount = rand() %9 + 2; /*Generates random number for player 1's amount of cards */
int player2_amount = rand() %9 + 2; /*Generates random number for player 2's amount of cards */
int a = 1; /* For loop purposes */
while(a <= 1) /* While loop to print out each player's amount of cards once */
{
printf("Player 1 you have %d cards! \n", player1_amount);
Sleep(500);
printf("Player 2 you have %d cards! \n", player2_amount);
a++;
}
Sleep(1000); /* Delays for 1 second before printing card values */
int values[3]; /* Creates an array with 3 elements, but I want the number of elements to be player1_amount from above */
int b; /* Random variable for the loop */
int size = sizeof(values) / sizeof(values[0]); /* Gets length of array */
for (b = 0; b < size; b++) /* For loop randomises 3 values and then stops */
{
values[b] = rand() % 10 +1;
}
printf("Player 1 your cards are"); /* For loop to print out the values one after the other */
for(b = 0; b < size; b++)
{
printf(" %d, ", values[b]);
}
getch();
return 0;
}
I believe you will want to use malloc or calloc for that with a pointer.
int *values = (int *)calloc(player1_amount, sizeof(int));
Just make sure you free your allocation when done:
free(values);
C allows you to declare variable sized array. If you are not interested in using functions like malloc or calloc you can simply use variable to declare array as I've done here :
#include <stdio.h>
void main()
{
int x;
printf("\nEnter the value of x : ");
scanf("%d" , &x);
int array[x];
for(i = 0 ; i < x ; i++)
{
printf("Enter the element : ");
scanf("%d" , &array[i]);
}
for(i = 0 ; i < x ; i++)
{
printf("%d " , array[i]);
}
}
This program runs correctly without any error. So your problem is solved here itself without using malloc or calloc. But just make sure you declare your array after scanning or giving value to your variable which will represent the size of your array(here : x is the variable) and in your case I guess : player1_amount.
But still if you want to use malloc then here it goes :
#include <stdio.h>
#include <stdlib.h>
void main()
{
int x , i;
int * array;
printf("\nEnter the value of x : ");
scanf("%d" , &x);
array = (int *) malloc(x * sizeof(int));
for(i = 0 ; i < x ; i++)
{
printf("Enter the element : ");
scanf("%d" , &array[i]);
}
for(i = 0 ; i < x ; i++)
{
printf("%d " , array[i]);
}
}
Both the codes will give you same output.
A little explanation ...
Malloc will take input parameter as the amount of memory you wish to allocate to given variable(like 'array' in our case) in bytes and will output the pointer to that block of memory.
Since here we are working with integer array the return type is cast as : (int *), had it been a character array we would type cast it as : (char *).

Proper use of structures and pointers

I have to declare a vector with the "struct" type which, for every n students, it creates a value for the group that student belongs to (which is like a counter), their names and their grades.
The program has to output the name of the students with the highest grade found in these groups. I have to allocate the vector on the heap (I only know the theoretical explanation for heap, but I have no idea how to apply it) and I have to go through the vector using pointers.
For example if I give n the value 4, there will be 4 students and the program will output the maximum grade together with their names as shown here.
This will output Ana 10 and Eva 10.
I gave it a try, but I have no idea how to expand it or fix it so I appreciate all the help I can get with explanations if possible on the practical application of heap and pointers in this type of problem.
#include <stdio.h>
#include <stdlib.h>
struct students {
int group;
char name[20];
int grade;
};
int main()
{
int v[100], n, i;
scanf("%d", n);
for (i = 0; i < n; i++) {
v[i].group = i;
scanf("%s", v[i].name);
scanf("%d", v[i].grade);
}
for (i = 0; i < n; i++) {
printf("%d", v[i].group);
printf("%s", v[i].name);
printf("%d", v[i].grade);
}
return 0;
}
Here I was just trying to create the vector, nothing works though..
It appears, int v[100]; is not quite what you want. Remove that.
You can follow either of two ways.
Use a VLA. After scanning the value of n from user, define the array like struct students v[n]; and carry on.
Define a fixed size array, like struct students v[100];, and use the size to limit the loop conditions.
That said,
scanf("%d", n); should be scanf("%d", &n);, as %d expects a pointer to integer type argument for scanf(). Same goes for other cases, too.
scanf("%s", v[i].name); should better be scanf("%19s", v[i].name); to avoid the possibility of buffer overflow by overly-long inputs.
Even though you are asking for the number of students (groups) using scanf, you hardcoded the upper bound of this value using v[100]. So, I passed your input variable n (the number of students) to malloc in order to allocate the space you need for creating an array of n students.
Also, I used qsort to sort the input array v where the last element would be the max value. Here qsort accepts an array of structs and deference the pointers passed to the comp function to calculate the difference of the comparison.
Finally, I printed the sorted array of structs in the last loop.
#include <stdio.h>
#include <stdlib.h>
struct students {
int group;
char name[20];
int grade;
};
int comp(const void *a, const void *b)
{
return ((((struct students *)a)->grade > ((struct students *)b)->grade) -
(((struct students *)a)->grade < ((struct students *)b)->grade));
}
int main()
{
int n;
printf("Enter number of groups: ");
scanf("%d", &n);
printf("\n");
struct students *v = malloc(n * sizeof(struct students));
int i;
for(i = 0; i < n; i++)
{
v[i].group = i;
printf("\nName: ");
scanf("%s", v[i].name);
printf("Grade: ");
scanf("%d", &v[i].grade);
}
qsort(v, n, sizeof(*v), comp);
for(i = 0; i < n; i++)
{
printf("Group %d, Name %s, grade %d\n", v[i].group, v[i].name, v[i].grade);
}
return (0);
}
You need to replace the standalone array v[100], with an array of structs referencing your structure:
struct students v[100];
However, if you want to use malloc to allocate memory on the heap, you will need to do something like this:
struct students *students = malloc(n * sizeof(struct students));
/* Check void* return pointer from malloc(), just to be safe */
if (students == NULL) {
/* Exit program */
}
and free the requested memory from malloc() at the end, like this:
free(students);
students = NULL;
Additionally, adding to #Sourav Ghosh's answer, it is also good to check the return value of scanf(), especially when dealing with integers.
Instead of simply:
scanf("%d", &n);
A more safe way is this:
if (scanf("%d", &n) != 1) {
/* Exit program */
}
With all this said, your program could look something like this:
#include <stdio.h>
#include <stdlib.h>
#define NAMESTRLEN 20
typedef struct { /* you can use typedef to avoid writing 'struct student' everywhere */
int group;
char name[NAMESTRLEN+1];
int grade;
} student_t;
int
main(void) {
int n, i;
printf("Enter number of students: ");
if (scanf("%d", &n) != 1) {
printf("Invalid input.\n");
exit(EXIT_FAILURE);
}
student_t *students = malloc(n * sizeof(*students));
if (!students) {
printf("Cannot allocate memory for %d structs.\n", n);
exit(EXIT_FAILURE);
}
for (i = 0; i < n; i++) {
students[i].group = i;
printf("Enter student name: ");
scanf("%20s", students[i].name);
printf("Enter students grade: ");
if (scanf("%d", &(students[i].grade)) != 1) {
printf("Invalid grade entered.\n");
exit(EXIT_FAILURE);
}
}
printf("\nStudent Information:\n");
for (i = 0; i < n; i++) {
printf("Group: %d Name: %s Grade: %d\n",
students[i].group,
students[i].name,
students[i].grade);
}
free(students);
students = NULL;
return 0;
}

Best way to resize/size arrays while the program is running

I am trying to take in array which contains some integer values/string values from the user, and not sure how long the array is going to be.. If i intitalise like array[500], i know it is a poor solution and poor programming skills.. How do i improve this?
Sample code below:
int main(void){
int t=0;
char str[200];
int count[20];
printf("Please enter the number of test cases(between 1 to 20):");
scanf("%d",&t);
for ( int i = 1; i<=t;i++)
{
printf("Please enter each of %i test case values:",i);
gets(str);
//set_create(str);
printf("\n");
}
for(int i = 0;i<t;i++)
{
prinf("%i",count[i]);
printf("\n");
}
return 0;
}
The code above is wrong definitely.. Need some help to improve the code...Thanks
Edited code:
int main(void){
int T=0;
int *count;
printf("Please enter the number of test cases(between 1 to 20):");
scanf("%d",&T);
count = malloc(T * sizeof *count);
for ( int i = 1; i<=T;i++)
{
printf("Please enter each of %i test case values:",i);
fgets(count);
printf("\n");
}
return 0;
}
Just use a pointer and malloc / realloc memory as needed. Don't use gets - it's unsafe and no longer in the standard. Use fgets instead.
For example, if you don't know how many count elements you need:
int *count;
scanf("%d", &t);
count = malloc(t * sizeof *count);
In such situation you can allocate memory for array in heap with functions malloc/calloc or on the stack with function alloca() (in header "alloca.h");

Resources