C - random numbers array function [duplicate] - c

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 5 years ago.
I'm trying to create a function that creates an array in size n with random numbers stored inside, I've been trying several option but once i use the array in main, only the first number shows up correctly.
I'm using CodeBlock by the way.
static int *arr;
int i, num;
printf("enter the length of the array: ");
scanf("%d/n", &num);
arr = get_random_arr(num);
for(i=0;i<num;i++)
{
printf("outside the function: %d\n", *(arr+i));
}
return 0;
int *get_random_arr(int num)
{
int temp_arr[num];
int i;
srand((unsigned)time(NULL));
for (i=0;i<num;i++)
{
temp_arr[i] = rand() % 1001 ;
printf("inside the function: %d\n",temp_arr[i]);
}
return temp_arr;
}
and this is the code that compiles:
enter the length of the array: 3
inside the function: 224
inside the function: 774
inside the function: 60
outside the function: 224
outside the function: 2686648
outside the function: 1977872892
Thank's to "coderredoc" his answer was the solution i was looking for

scanf("%d/n", &num);
You have to enter the number followed by / and n. This is not what you want. You wanted this
scanf("%d\n", &num);
But here the scanf reads the number in num but then the reading continues until nonwhitespace character followed by \n is found. You don't need the \n here.
Also returning return temp_arr; and using it outside it's scope is UB.
The array temp_arr has automatic storage duration meaning its lifetime will end after the function ends. Accessing it outside its scope is undefined behavior which is precisely what you did.
Something like this
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int *get_random_arr(int num)
{
if( num <= 0){
fprintf(stderr, "%s\n", "Error in the number: num >= 1");
exit(1);
}
int *temp_arr = (int*)malloc( sizeof *temp_arr *num);
if( !temp_arr ){
fprintf(stderr, "%s\n", "Error in malloc");
exit(1);
}
srand((unsigned)time(NULL));
for(size_t i=0;i<num;i++)
{
temp_arr[i] = rand() % 1001 ;
printf("inside the function: %d\n",temp_arr[i]);
}
return temp_arr;
}
int main(){
static int *arr;
int num;
printf("enter the length of the array: ");
if( scanf("%d", &num) != 1){
fprintf(stderr, "%s\n","Error in input" );
exit(1);
}
arr = get_random_arr(num);
for(size_t i=0;i<num;i++)
{
printf("outside the function: %d\n", *(arr+i));
}
free(arr);
return 0;
}
The code tries to show a possible way to achieve what you wanted. Dynamically allocated memories lifetimes extends beyond the scope of the function. That's why it works. Note the free() - which is used to free the dynamically allocated memory.

The first and foremost, in your code, temp_arr is local to the function get_random_arr(). Once the function finishes, the returned address is not valid anymore!
The moment you try to use the returned value, it causes undefined behavior, as the accessed memory is invalid in the context of the caller.
That said, not checking the return value of scanf() also posses a problem. In case scanf() fails, you'll be end up using an unitialized value.

Related

Passing an array as a parameter to another function in C

I fairly new to C and am currently trying to use some parameters from one function in another function.
Essentially from function1 (which asks the user to input an array and return its size) I need to pass the whole array and its size as parameters to function2 which will then print them out to screen/file in the format shown in this image.
How can I create another separate function that uses the array and size of function1 in order to give me the desired output as described above.
For reference, this is the code for function1:
(I made use of a header as these two functions will later on be implemented into a menu)
#include <stdio.h>
#include "function1.h"
//Main
int main(void) // Without the explicit "void" argument list, this isn't a full function definition
{
int size;
printf("The size of list: ");
if (scanf("%d", &size) != 1 || size < 1) { // You should ALWAYS check the return value of a scanf call
printf("Invalid size input.\n");
return 1;
}
int marks[size]; // Need to specify the size and note that you cannot initialize a VLA
if (size >= 200) {
printf(" Limit exceeded.\n");
return 2;
}
intarray(marks,size);
return 0;
}
And the header file for function1 is:
#ifndef FUNCTION1_H
#define FUNCTION1_H
int intarray(int ar[], int size){
printf("Please enter %d values:\n"); // You need to give "size" as an argument
for (int i = 0; i < size; i++) {
scanf("%d", &ar[i]); // You should add a check for valid input here, as I have done in main
}
printf("Elements in array are: ");
for (int i = 0; i < size; i++) {
printf("%d, ", ar[i]);
}
printf("\n");
printf("Size of array is: %d", size);
}
#endif //FUNCTION1_H

How initialize array dynamically using function in C

SS4SS of 3rd Problem
I want to create the program to take the input from user until he presses 1.
I'm using dynamic memory allocation using function and after running this code, this program takes only 4 input and it does not show any output
output
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void input(int **arr)
{
int n=1,i=0;
*arr=(int *)malloc(sizeof(int));
int ch;
do
{
printf("\nEnter '1' To Enter A Value in array or else enter '0'");
scanf("%d",&ch);
if (ch==1)
{
if (!*arr)
{
printf("\nInsufficient Memory!");
return;
}
printf("\nEnter the value\t:\t");
scanf("%d", arr[i]);
*arr=realloc(*arr,sizeof(int)*(++n));
*arr[++i]=INT_MIN;
}
else if (ch!=1&&ch!=0)
{
printf("\nInvalid input!");
continue;
}
} while(ch!=0);
free(arr);
}
void display(int **arr)
{
for (int i = 0; i < 3; i++)
printf("\n%d", **(arr+i));
free(arr);
}
int main()
{
int *arr;
input(&arr);
display(&arr);
free(arr);
return 0;
}
First question
With !*arr[i] you are checking the logical value contained in *arr[i], which can have a random value before you assign a value to it. In your case, the value contained in *arr[i] is 0, triggering the condition !*arr[i].
The correct way of checking if realoc() was succesful, is checkin it's returned value. If it's null, the request failed. In your case, it would be replacing
if(!*arr[i])
by
if(!*arr)
Second question
In this line *arr[++i]=INT_MIN; the index [] operator has precedence over pointer * operator. You have to write parenthesis:
(*arr)[++i]=INT_MIN;
And also here
scanf("%d", arr[i]);
you are saying that arr is an array, when it is a pointer to an array. You should replace it with:
scanf("%d", *arr + i);
Third question
You are also doing free() before you access the values in the array, which triggers the error. You should remove the free() calls at the end of input() and display() and leave only the one of the end of main().
You have still to replace the printf() in display with
printf("\n%d", (*arr)[i]));

Extreme sum values calculated inside a structure

While I was learning to code in C about structure and pointers, I tried to make a program that calculate grades of students.
I thought it would work from my previous experiences for such calculation without pointers and structure. But with those, it gave me wild results in the program.
#include <stdio.h>
#include <string.h>
/*
The program will scan year, name, score of three different subjects,
and calculate the sum and the average.
Three different people (using array) will be taken into account.
*/
struct grade {
int year;
char name[20];
int score[3];
int total;
float avg;
};
void main() {
struct grade p[3];
char str = 'c';
char *pstr = NULL;
int i, j;
pstr = &str;
for (j = 0; j < 3; j++) {
printf("Year of Admission: ");
scanf("%d", &p[j].year);
printf("Name of the Student: ");
scanf("%s", pstr);
strcpy(p[j].name, pstr);
for (i = 0; i < 3; i++) {
printf("The score for Subject %d: ", i + 1);
scanf("%d", &p[j].score[i]);
p[j].total += p[j].score[i];
}
p[j].avg = p[j].total / 3.0;
}
for (j = 0; j < 3; j++) {
printf("%s's\n", p[j].name);
printf("Total score: %d\n", p[j].total);
printf("Average: %.2f\n", p[j].avg);
}
}
I could have written each of three different subjects as one variable but for an extra "challenge", I made an array inside the structure.
int score[3];
However, the program only prints out extremely small number -89541694... for both totals and averages.
I assume that this particular line inside a for-loop is a problem.
scanf("%d", &p[j].score[i]);
But I could not figure out why. I am really new to pointers and still learning them.
I hope for your generous teaching and explanations.
Thank you in advance.
Local variables are not initialized with 0, so you just need to zero it before calculating total:
p[j].total = 0;
before
for (i = 0; i < 3; i++) {
printf("The score for Subject %d: ", i + 1);
scanf("%d", &p[j].score[i]);
p[j].total += p[j].score[i];
}
The variable pstr points to a single char. A string in C needs to be at least two characters for a single-character string: The actual character, and the null terminator.
When you use e.g. scanf to read a string, the function will write at least two bytes to the memory pointed to by pstr. But since it only points to a single byte you will write out of bounds and that leads to undefined behavior.
If you want to be able to read more than a single character you need to have more space allocated for the string. And you need to limit scanf so it will not write out of bounds.
For example
char pstr[40]; // Allows for strings up to 39 character, plus terminator
// ...
scanf("%39s", pstr); // Read at most 39 characters from standard input, and write to pstr
Another problem is that local variables are not automatically initialized, their values will be indeterminate.
That means the contents of the array p is unknown and seemingly random.
When you do
p[j].total += p[j].score[i];
you use the seemingly random value of p[j].total to calculate another seemingly random number.
To initialize all structures and all their members to "zero" in the array, do e.g.
struct grad p[3] = { 0 };
Instead of making pstr a pointer you might wanted to do somehting like this
char pstr[30];
And accordingly you will scanf the string using scanf("%29s",pstr); and check it's return value.
To describe the problem a bit - you had a pointer pointing to a char which is not capable of holding an input characters and the corresponding \0 (nul terminating character). As a result this gives rise to undefined behavior. And then using it in strcpy is also an illegal code. (Undefined behavior).
Here the solution I gave simply declared an array of 30 characters and we limited the string input using scanf upto 29 characters because we need to store the terminating null.
Showing you atleast a bit of code to make you understand how to write these codes:-
if( scanf("%29s",pstr)!= 1){
fprintf(stderrm"Error in input");
exit(EXIT_FAILURE);
}
Another problem is initialize the variables - here you used p[j].total += p[j].score[i]; What is the value of p[j].total initially. It contains garbage value. In the loop make p[j].total = 0; first. That will give you the correct result.
Note: The wild results are the garbage value resulted from addition of some garbage value with p[j].score[i].
Also note that without making the changes that I said if you only change the initialization thing then also code is not guranteed to work. undefined behavior is undefined behavior - cases may arise which will simply crash the program making you wonder where you went wrong.
Illustration code may help you:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
The program will scan year, name, score of three different subjects,
and calculate the sum and the average.
Three different people (using array) will be taken into account.
*/
struct grade {
int year;
char name[20];
int score[3];
int total;
float avg;
};
int main(void) {
struct grade p[3];
char pstr[20];
int i, j;
for (j = 0; j < 3; j++) {
printf("Year of Admission: ");
if(scanf("%d", &p[j].year)!=1){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
printf("Name of the Student: ");
if(scanf("%19s", pstr)!=1){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
strcpy(p[j].name, pstr);
p[j].total = 0;
for (i = 0; i < 3; i++) {
printf("The score for Subject %d: ", i + 1);
if(scanf("%d", &p[j].score[i])!=1){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
if(p[j].score < 0){
fprintf(stderr, "%s\n", "Error in input");
exit(EXIT_FAILURE);
}
p[j].total += p[j].score[i];
}
p[j].avg = p[j].total / 3.0;
}
for (j = 0; j < 3; j++) {
printf("%s's\n", p[j].name);
printf("Total score: %d\n", p[j].total);
printf("Average: %.2f\n", p[j].avg);
}
return 0;
}
In fact instead of using the pstr just input the names directly in the structure variable instance itself. No need to use a temporary variable.

Defining malloc array size with scanf and initialising

I'm trying to create a program that asks the user for a size of an array, then asks the user to populate it.
Whenever I launch the program, the "Element %d" printf displays the %d as a large number instead of 1.
If I continue the program after entering the value into the array, the debugger crashes. What's happening here? Did I accidentally place the address in the array position? Thanks
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int elements = 0;
printf("How many Elements will you enter?");
scanf("%d", &elements);
int* elementArray = malloc(sizeof(int) * elements);
int i = 0;
while (elementArray[i] != '\0')
{
printf("Element %d: ", elementArray[i]);
scanf("%d", &elementArray[i]);
i++;
}
free(elementArray);
return 0;
}
EDIT: Reading the comments, I meant printf("Element %d: ", elementArray[i]); was supposed to print one during the first loop. Though I should edit the code to be elementArray[i] + 1 so it doesn't print "Element 0" instead of Element 1. Apologies for the barebones code, it's half finished, I wanted to solve this problem before finishing it off. Will work on the solutions given now. Thanks for the help
EDIT2: Thanks to all of you, especially Sharuya! Here's my finished code.
void printArray(int* elemArray, int elements)
{
printf("The Array contains: ");
for (int k = 0; k < elements; k++)
{
printf("%d,\t", elemArray[k]);
}
}
int main(void)
{
int elements = 0;
printf("How many Elements will you enter?");
scanf("%d", &elements);
int* elementArray = (int *)malloc(sizeof(int) * elements);
int input = 0;
for (int j = 0; j < elements; j++)
{
printf("Element %d: ", j + 1);
scanf("%d\n", &input);
*(elementArray + j) = input;
}
printArray(elementArray, elements);
free(elementArray);
return 0;
}
Only issue now is, between the "Element 1: " and "Element 2: " printf, I get a blank line, that allows me to enter a number, upon submitting, it continues as normal. If I submit an array with 5 elements, It asks me for 6 elements, and only 5 appear... What's happening here?
while (elementArray[i] != '\0')
This check is the problem
malloc gives no guarantee that the memory initialized will be zero filled. Hence your loop may cross over the allocated memory and try to read memory that your program is not supposed to read (hence resulting in a crash)
If it's zero filled your code will never enter the loop
What you need is
while (i < elements)
Also printf should come after scanf for any meaningful result. If you want to just get the index that you are about to enter use printf("Element: %d", i) instead of elementArray[i]
A couple of questions, for you to ask:
What if the user enters a negative value?
What if the user enters 0 ?
What if the user enters a very large value?
Did the array allocation succeed?
What is in my array after it is allocated?
If my array size is 0, will elemenArray[0] be valid?
Should I use a for loop, like everyonbe else does for walking through my array?
Just asking yourself these questions will fix this program in no time, and will get you through half of the next one you'll write.
You have more problems than the fact that you print something else than the index.
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int elements = 0;
printf("How many Elements will you enter? ");
if((1!=scanf("%d", &elements))||(elements<1) ) // check return value, always a good idea
{ printf("Reading number failed.\n");
return 1;
}
int* elementArray = malloc(sizeof(int) * elements);
int i = 0;
while ( (i<elements) // use the number you asked for to avoid writing beyond array
&& ((0==i) || (0 != elementArray[i-1]))) // stop when previously entered value is 0
{
printf("Element %d: ", i+1); // print the index
// instead of the non-initialised value
if(1!= scanf("%d", &elementArray[i]))
{
printf("Reading value failed!\n");
free(elementArray); // cleanup
return 1;
}
i++;
}
if (i<elements)
{
printf("Stopped early because 0 was entered.\n");
}
free(elementArray);
return 0;
}
First you need to know that malloc() function dynamically allocates memory according to the size calculated (with the help of sizeof() ) and returns the address of this memory location.
However this address is not associated with any data type i.e. only a void* pointer can store this address of an incomplete data type.
Thus instead of mentioning
int* elementArray = malloc(sizeof(int) * elements);
mention and use typecasting to it
int* elementArray = (int *)malloc(sizeof(int) * elements);
As per your code, elementArray is a pointer which will store the address of an integer
int *elementArray;
printf("Element %d: ", elementArray[i]);
Thus the above line will actually print the address pointed to by the pointer and not the index since incrementing a pointer is same as
elementArray stores the base address.
i.e elementArray++ is equal to elementArray+1 == elementArray[1] will point
to the next memory location after 4 bytes.(since integer is stored in 4 bytes)
I have modified your code correcting your mistakes
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int elements = 0;
printf("How many Elements will you enter?");
scanf("%d", &elements);
//the below statement actually allocates contiguous block of memory equal
//to no of elements and the pointer points only to first element.
//Incrementing it will point to next element
int* elementArray =(int *) malloc(sizeof(int) * elements);
//typecasting of void* pointer to int*
int i = 0,elm;
for(i=0;i<elements;i++)
//Since u know iterations will be equal to no of elements it is better to use for loop
{
printf("Element %d: ", i);
scanf("%d", &elm);
*(elementArray+i)=elm;
//Storing the data in elm and making the pointer point to next free
//dynamically allocated block of memory and using * operator the value at
//this location is accessed and storing elm value in it
}
for(i=0;i<elements;i++)
printf("%d",*(elementArray+i));
free(elementArray);
return 0;
}
This code works and I hope it make things clear !!!

Endless loop in C; for loop seems valid

I am a student trying to learn c coming from c++. I wrote the following code and it compiles fine; however, when I execute it I get an endless loop when calling the print function. I looked over the code and it seems to be valid to me, so why is it printing an endless loop?
#include <stdio.h>
#include <stdlib.h>
struct student
{
int id;
int score;
};
void generate(struct student *students, int n)
{
int randomId = rand () % n + 1;
int randomTestScore = rand() % 100 + 1;
students->id = randomId;
students->score = randomTestScore;
}
void sort(struct student *students, int n)
{
/*using insertion sort*/
for (unsigned int i = 1; i < n; ++i)
{
int next = students[i].score;
int j = i;
while(j > 0 && students[j-1].score > next)
{
students[j].score = students[j-1].score;
j--;
}
students[j].score = next;
}
}
void print(struct student *students, int n)
{
for (unsigned int i = 0; i < n; i++)
{
printf("Student at position No: %d Test Score: %d\n", i+1, students[i].score);
}
}
int main()
{
/*user enters num of students to create scores for*/
int num_students;
printf("Enter Num of students\n");
scanf("%d", num_students);
/*allocate memory for the amount of students user wants*/
struct student *userStudents = malloc(num_students*sizeof(struct student));
printf("Randomly filling students IDs & Test Scores...\n");
for (unsigned int i = 0; i < num_students; ++i)
{
generate(&userStudents[i], num_students);
}
printf("Array of students before sorting:\n");
print(userStudents, num_students);
printf("\nNow, sorting students by test scores...\n\n");
sort(userStudents, num_students);
printf("Array of students after sorting:\n");
print(userStudents, num_students);
return 0;
}
To use scanf() correctly it needs to alter the passed variable in place, and since there is no pass by refrence in c, you need to pass the address of the variable, so scanf() is able to modify it though a pointer, hence you need to use the & operator, but that is not enough.
The scanf() family of functions, return a value that must be checked before you can access the scanned values, you should never ignore that value, under any circumstances you should check for it.
What your code is doing is called undefined behavior, it's interpreting the passed integer as if it was a pointer, which is undefined behavior.
To prevent that you can activate compiler warnings, many compilers know what kind of parameter the *f functions expect, i.e. the functions which take a string as a format to be parsed and to allow the function to correctly grab the rest of the parameters passed via variable arguments to it.
The correct way to call scanf() in your program is
if (scanf("%d", &num_students) != 1)
return 1;
that is, from main() and hence it's ending the program, because you can't continue after that condition was true, in that case what actually happens is that num_students is not initialized, that would once again cause undefined behavior.
Change the call to scanf to:
/*
* correct way of calling scanf, passing the address of the wanted variable
*/
scanf("%d", &num_students);
^
This elliminates segmentation faults and makes the code runs OK on my machine.
I had a previous hint that you'd need to change your declaration of userStudents to a pointer to pointers, however I was incorrect. You are clearly correctly allocating enough contiguous memory to hold all of your structs pointed by *userStudents.

Resources