Endless loop in C; for loop seems valid - c

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.

Related

Segmentation Fault linear search algorithm

This algorithm is a linear search algorithm that finds the desired value. But when I compile this code, gives the segmentation fault in if(dizi[i]==aranan) this line. How can I solve this ?
#include <stdio.h>
int N,i,aranan;
int ArrayBastir(int *dizi,int N)
{
printf("My numbers\n");
for(int i =0; i<N;i++)
{
printf("%d\n", dizi[i]);
}
}
int findValue()
{
printf("The value you want to search");
scanf("%d",&aranan);
}
int Output(int *dizi,int N,int aranan)
{
for(int i =0; i<N;i++)
{
if(dizi[i]==aranan)
{
printf("%d number %d. found in queue \n", aranan,i+1);
}
}
}
int main() {
int N;
int aranan;
printf("Please enter how many numbers you want to enter");
scanf("%d", &N);
int dizi[N];
for(int i =0; i<N;i++)
{
scanf("%d", &dizi[i]);
}
ArrayBastir( dizi, N);
findValue(aranan);
Output(*dizi,N,aranan);
return 1;
}
Linear Search algorithm
You have two objects defined as:
int aranan;
Once is defined at file scope (a global), and one is defined within the scope of main.
When findValue(aranan) is called, a copy of the uninitialized value of aranan within the scope of main is passed to findValue. findValue is lacking a prototype, having not declared its arguments, so this is ignored.
findValue scans a value into the file scope aranan, but when Output(*dizi, N, aranan) is called it uses the value of aranan defined within main. aranan within main was never initialized, and thus this causes Output to search for an indeterminate value.
Additionally, *dizi is an int, when Output expects an int * as its first argument.
ArrayBastir and Output are also defined as each returning an int, which they do not do.
You should not ignore the return value of scanf, as it indicates the number of successful conversions, or a negative value on failure (EOF). In a program this small, you can get away with writing a simple wrapper function for reading integers, that just exits the program if the user enters something invalid.
main returning nonzero generally indicates your program failed. main is special - it is the only non-void function where you can omit a return statement. If main reaches the end of execution without an explicit return, it is treated as though it returned 0.
The issues above can be mitigated by avoiding the use of global variables, and by turning up your compilers warning level to catch obvious type mismatches.
For GCC or Clang, use -Wall -Wextra, and possibly -Werror.
For MSVC, use /Wall, and possibly /Wx.
Minimally refactored:
#include <stdio.h>
#include <stdlib.h>
int get_int(void)
{
int x;
if (1 != scanf("%d", &x)) {
fprintf(stderr, "Invalid input.\n");
exit(EXIT_FAILURE);
}
return x;
}
void ArrayBastir(int *dizi, int N)
{
printf("My numbers\n");
for (int i = 0; i < N; i++) {
printf("%d\n", dizi[i]);
}
}
void Output(int *dizi, int N, int aranan)
{
for (int i = 0; i < N; i++) {
if (dizi[i] == aranan) {
printf("Found <%d> at position %d.\n", aranan, i);
}
}
}
int main(void)
{
printf("Please enter how many numbers you want to enter: ");
int N = get_int();
int dizi[N];
for (int i = 0; i < N; i++) {
dizi[i] = get_int();
}
ArrayBastir(dizi, N);
printf("Enter the value you want to search for: ");
int aranan = get_int();
Output(dizi, N, aranan);
}

C - "Error: Invalid operands to binary != ..."

I seem to not be able to find the problem to make the program work. C is telling me "error: Invalid operands to binary != 'grocerylist' (aka struct grocerylist) and 'int' When i try to solve this problem other bugs pop out, can anyone see other problems in this code except for the bug I posted about?
#include <stdio.h>
#include <stdlib.h>
#define MAX 100
typedef struct grocerylist
{
char name[MAX];
float ammount;
char unit[MAX];
} grocerylist;
struct grocerylist * enterItems(int arr)
{
grocerylist * itemtolist;
itemtolist = (grocerylist*)malloc(sizeof(grocerylist)*arr);
if (*itemtolist != 0)
{
int i;
for(i = 0; i < arr; i++)
{
printf("Enter item name: /n");
scanf("%c", (itemtolist[i]).name);
printf("Enter ammount of item: /n");
scanf("%f", &(itemtolist[i]).ammount);
printf("Enter unit of item: /n");
scanf("%c", (itemtolist[i]).unit);
}
}
return itemtolist;
}
void printShoppingList(grocerylist *itemtolist, int arr)
{
int i;
for (i = 0; i < arr; i++)
{
printf("%s, %f, %s", itemtolist[i].name, itemtolist[i].ammount,
itemtolist[i].unit);
}
}
int main(void)
{
int arr, number;
grocerylist * itemtolist;
while (number == 0)
{
printf("How many items would you like to add to your list? /n");
scanf("%i", &arr);
itemtolist = enterItems(arr);
printShoppingList(itemtolist, arr);
free(itemtolist);
printf("Do you want to enter another item. 0 for yes, 1 for no");
scanf("%i", &number);
}
return 0;
}
You want to check that itemtolist itself (a pointer) isn't a null pointer.
But instead, your code attempts to compare *itemtolist (the pointed-at list), which isn't comparable to 0.
This fragment should be improved:
grocerylist * itemtolist;
itemtolist = (grocerylist*)malloc(sizeof(grocerylist)*arr);
if (*itemtolist != 0)
I'd write this as:
grocerylist *itemtolist = malloc((sizeof *itemtolist) * arr);
if (itemtolist)
Notes:
itemtolist != 0 is equivalent to just itemlist here in a boolean context. You can write it the long way if you want, but the short form is probably more idiomatic in C.
We don't cast the result of any of the malloc() family of functions.
Use the sizeof operator on the *itemlist so it automatically uses the correct type.
Initialize the variable as you declare it - that helps avoid accidentally using unintialized variables (but your compiler warnings should include that).
Also note that you really ought to check the return value from scanf() - I assume you removed the checking to make your example short for the question. You will need to change %c to %99s, but again, compiling with gcc -Wall or equivalent will help you spot that.

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 !!!

Scanf in to array

This a dot_product function of 2 vectors of the same length.
I don't understand how to build the array because how the machine will know which input goes to which input (for example i want a={1,2,3} but the input of 123 will come a[0]= 123)...
How do I make end of array[index] input and how do I make end of the whole array.
#include <stdio.h>
#include <stdlib.h>
#define MAXINPUT 100
int dot_product(int v[], int u[], int n)
{
int result = 0;
int i;
for (i=0; i < n; i++)
result += v[i]*u[i];
return result;
}
int main(){
int v1[MAXINPUT];
int v2[MAXINPUT];
int count = 0
int i,print;
printf(" first vector:");
for(i=0;i<MAXINPUT;i++){
scanf("%d", &v1[i]);
count +=1;
}
printf(" second vector:");
for(i=0;i<MAXINPUT;i++)
scanf("%d", &v2[i]);
print = dot_product(v1, v2, count);
printf("v1*v2:%d",print);
return 0;
}
The first problem I observe here is with
count +=1;
where count is an uninitialized automatic local variable, which makes it's initial value indeterminate. Attempt to use that value invokes undefined behavior.
You should be initializing count to 0.
That said, here, you're depending on the user to input the second array with exact same dimension of that of the first one. In case that does not happen, your program will blow up, as you did not initialize the arrays, again.

How to assign value to procedure's struct parameter?

I'm making a program to input some data to array of struct. When I tried to assign temporary struct temp to procedure's struct parameter *daf, the program's always force closed. Here's my code:
#include <stdio.h>
typedef struct {
int num;
char name[50];
float value;
} Mhs;
typedef Mhs ListMhs[50];
void inputData(int nEf, ListMhs *daf);
int main() {
ListMhs listmhs;
inputData(5, &listmhs);
return 0;
}
void inputData(int nEf, ListMhs *daf) {
int i;
ListMhs temp;
for (i=0; i<nEf; i++) {
printf("Num: ");
scanf("%d", &temp[i].num);
printf("Name: ");
scanf("%s", &temp[i].name);
printf("Value: ");
scanf("%f", &temp[i].value);
}
//assign value
for (i=0; i<nEf; i++) {
*daf[i] = temp[i];
}
}
Your problem lies in the line *daf[i] = temp[i];
[] has higher precedence than *
So it should be (*daf)[i] = temp[i];
The original line *daf[i] = temp[i]; is actually *(daf[i]) = temp[i];and was trying to treat daf as an array of ListMhs and taking the ith element of it and then dereferencing it. Obviously as you were only passing in a pointer to one ListMhs, as soon as i was greater than 0 you would have problems. The program probably tried to write to protected memory after the second or third iteration, which is why it hard crashed. If you had a debugger of some sort attached you would have probably got a more helpful error.
Here is the list of C++ operator precedence: http://en.cppreference.com/w/cpp/language/operator_precedence

Resources