For an assignment, I have to declare a struct as follows:
struct Food
{
char *name;
int weight, calories;
} lunch[5] = {
{
"apple", 4, 100
},
{
"salad", 2, 80
}
};
In my main, I am trying to ask the user for the rest of the inputs to fill the struct to print them out. I figure I would try to use malloc. Would I do something like this?
int main(void)
{
char *str1;
printf("Please enter a food, weight, and calories of the food: ");
scanf("%s", (char *)malloc(str1));
return(EXIT_SUCCESS);
}
Well ... Not quite.
You just pass the result of malloc() to scanf(), and that function won't return it, you lose the pointer. This is generally a bad idea. Also, investigate what argument malloc() expects, you're not doing it right.
Consider first allocating the memory, using a pointer variable to store it, and then passing the value of that pointer to scanf(). Hint: you already have the pointer variable, in your array.
Also, you shouldn't cast the return value of malloc() in C, and return is not a function, so it shouldn't have parenthesis around its value.
You should rather allocate space for a new instance of Food, then allocate space for name. If all allocations succeed, then you can start asking the user for data.
You should look at your course material, read the books on the reading-list, or ask your lecturer.
If you must do your own research online, you should perhaps try to understand this example and google for similar how-tos.
Generally, you shouldn't use scanf for parsing user input. Its much more straightforward and robust to use getline to retrieve a line of user input, then utilities such as strdup and atoi to extract your values, one per line rather than on the same line, and check for error values and such.
Here is a small example of how I would go about this. Unfortunatley I cannot test the code and I am learning C myself at the moment, but maybe this will give you some ideas. This would just initialize the instance at lunch[2]. So you should add some sort of loop to fill the other instances.
int main(void)
{
lunch[2].name = (char*) malloc(/*The size of the string you want for the
name of your food. Every character has
the size of one byte (+'\0' at the end)*/)
printf("Please enter a name for your food: ");
scanf("%s", lunch[2].name);
printf("Please enter the weight of your food: ");
scanf("%d", &lunch[2].weight;
printf("Please enter calories of your food: ");
scanf("%d", &lunch[2].calories);
return EXIT_SUCCESS;
}
getline, strtok, strdup, atoi
the rest is left as an exercise :-)
Related
I have an assignment in C that basically asks for some sort of interface/database for a supposed animal shelter, and we were given these 2 structures:
typedef struct age
{
int years, months;
}age;
typedef struct pet
{
int id;
char* sex;
char* breed;
age* pet_age;
}pet;
The interface has to have several functions, like adding a new pet (in our case dogs specifically), removing based on ID, searching for all pets of the same breed and changing the name of a breed entirely, and it all has to be done dynamically using a pet* array as well as the malloc and realloc functions. The entries have to be written in a file and also read from it, but that's something I'll figure out after I figure out how to handle the functions regarding my dynamic array first.
To get to the point, I am having trouble understanding how to scan/reference an instance's pet_age. I've tried it a myriad different ways but I don't understand what's wrong, really. The program crashes/exits after I scan the months element.
Here is the insertion function I have implemented thus far. While not correct, the main source file still compiles.
void addPet(pet *p){
if(i=1){ //First time activation check.
p=malloc(k*sizeof(p));
if(!p){
printf("\nUnable to allocate memory...");
exit(0);
}
}
p[i].sex = malloc(sizeof(char)*1);
p[i].breed = malloc(sizeof(char)*20);
p[i].pet_age =malloc(sizeof(int)*2);
p[i].id = i; //Autogenerated ID
printf("\n%d\n", p[i].id);
printf("Insert pet's breed:"); //Scan breed
scanf("%s", p[i].breed);
printf("Insert pet's sex:"); //Scan sex
scanf("%s", p[i].sex);
printf("Insert pet's age in years:"); //Scan years
scanf("%d", p[i].pet_age->years);
printf("\n%d\n", p[i].pet_age->years);
printf("Insert pet's age in months:"); //Scan months
scanf("%d", p[i].pet_age->months);
printf("\n%d\n", p[i].pet_age->months);
i++; //Incrementing counter
if(i==k){
k+=10;
p=realloc(p, k*sizeof *p); //Size check
}
}
For now there is a basic initialization in the event that this is the first insertion. Then I allocate memory for each element of the structure (to the best of my understanding), and scan every element with a scanf (I pasted some printf checks to see what was actually scanned). Then at the end I increment the i counter, followed by a size check to allocate 10 more places for the array in the event that i==k.
For the sake of continuity, here is my main function as well (basic menu and all):
int i=1; //Counter
int k=10; //Default max entries
int main(int argc, char *argv[]) {
FILE *fp;
int choice;
pet *petarray;
//Menu that lists every option.
while(1){ //Endless loop that ends only if you choose to exit through the 5th option.
printf("\n\n Menu:");
printf("\n=========");
printf("\n1. Insert information for a new pet.");
printf("\n2. Delete a pet record based on pet's ID.");
printf("\n3. Search a pet record based on pet's breed.");
printf("\n4. Update pet's breed name.");
printf("\n5. Exit.\n\n");
scanf("%d", &choice);
switch(choice)
{
case 1:
addPet(petarray);
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
printf("Exiting program...");
exit(0);
}
}
return 0;
}
Apologies if this seems amateur, I'm quite the rookie and still learning. Thanks in advance.
It compiles, but don't you get a long list of warnings? If you don't, you should turn on warnings.
But let's have a look.
void addPet(pet *p)
{
if (i = 1)
You are not comparing (global!) i to 1 here. You are assigning to it. This if statement can only take the true path because of that. When you assign to i, the result of the assignment is the value you assign, so you are testing if (1) here. You want to take this path only if i is 1, I guess, so you should use if (i == 1).
{ //First time activation check.
p = malloc(k * sizeof(p));
Well, it is every time, but we have fixed that now. What do you want p to be, here? An array of k pets? That is not what you are allocating memory for. You are allocating space for k times sizeof(p) and since p is a pet *p, that means you are allocating space for k pointers to pets. Not pets. That, of course, is a problem since p is a pointer to pet and not a pet **. You have most likely allocated too little memory here.
This, unfortunately, is usually not something you will get a warning about. You can give malloc() any size, and it will give you that amount of memory. If you asked for the wrong amount, you get the wrong amount. I think you wanted malloc(k * sizeof *p) here. That allocates space for k of the kind of objects p points to, and that means you can use p as an array of k of that type. You do it the right way when you realloc() later, so this is probably just a quick mistake, but it can easily destroy everything at runtime.
p[i].sex = malloc(sizeof(char) * 1);
p[i].breed = malloc(sizeof(char) * 20);
Two issues here. First, are you sure that p has an entry i? If you fixed the allocation above, then the p you allocated the first time has room for k pets, but this could be any p we have called the function with, so we don't know about this one at all. There is absolutely no guarantee that it is valid to access p[i]. Your reliance on the two global variables will generally make this very dodgy; you simply cannot assume that the function is called with the specific pointer you allocated memory for a bit earlier.
Second, for the string allocation, there are a few red flags as well. sizeof(char) is always 1, so you don't need it. It isn't wrong, really, it just looks odd. And are you absolutely sure that you are allocating enough memory? For p[i].sex I find it highly unlikely. You are getting space for exactly one char. If you only want one char, then that is fine, but you you should probably declare sex a char instead of a char *. If you plan to put a string in p[i].sex, then it will have to be the empty string and nothing longer, because you have only room for the '\0' terminal in a buffer of length 1.
With
p[i].pet_age = malloc(sizeof(int) * 2);
it might technically work, but I don't think the standard guarantees it. You are allocating space for a struct age, and that struct holds two int. They will align the right way, so there shouldn't be any padding, and therefore it should work, but it is flaky as hell.
If you want to allocate space for a struct, then do that. malloc(sizeof(struct age)) gets the job done. Even better, gets the type from the variable you are allocating space for:
p[i].pet_age = malloc(sizeof *(p[i].pet_age));
If p[i].pet_age is a struct age *, then *(p[i].pet_age) is a struct age, and it is the size of that we want.
Then we read in the data.
printf("Insert pet's breed:"); //Scan breed
scanf("%s", p[i].breed);
Here we can have a buffer overflow.
printf("Insert pet's sex:"); //Scan sex
scanf("%s", p[i].sex);
Here we are guaranteed one, because we need to write the terminal zero into sex after we put the data there.
printf("Insert pet's age in years:"); //Scan years
scanf("%d", p[i].pet_age->years);
printf("\n%d\n", p[i].pet_age->years);
printf("Insert pet's age in months:"); //Scan months
scanf("%d", p[i].pet_age->months);
printf("\n%d\n", p[i].pet_age->months);
Since scanf needs to store the data it reads somewhere, it needs a pointer to where it should put it. You are providing integers. (Your compiler definitely should have warned you here). You should use &p[i].pet_age->years to store an integer in p[i].pet_age->years, and the same for months.
Then we get to what I think is probably the worst error in the code.
if (i == k)
{
k += 10;
p = realloc(p, k * sizeof *p); //Size check
}
I'm not going to comment on the global variables again, but rather the local variable. This realloc potentially destroys the memory that p pointed at. I don't care that it can return NULL and you don't check; I doubt that this is happening in your program, but someone called addPet with a pointer, and they have no way of knowing if that pointer is valid again after calling. They have to consider it lost. It won't be freed if addPet() doesn't free it (and it doesn't), and they cannot safely do it themselves. The new memory you allocate doesn't get back to the caller in any way. Assigning to the local variable in addPet() doesn't affect any caller's variable. This realloc() is dangerous. The caller will absolutely lose the existing memory and has no way of obtaining the new memory.
Any of these issues can be the cause of your current problem; the others can be the cause of future problems.
This function is supposed to save data to a library.books_count instance of a dynamic array of pointers to structures. Yet it does not. A similar function addexistingBooks() does it flawlessly. What is the problem in realloc()?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char book_name[32];
char book_genre[32];
char author[32];
int page_count;
float price;
}Sbook;
typedef struct
{
char library_name[32];
Sbook * bookp;
int books_count;
}Slib;
void menu(char String[50]);
void addexistingBooks(Slib library, int i);
void addBook(Slib library, int i);
int main()
{
Slib library;
int i=0;
char Choice[30];
printf("Enter amount of books inside the library: ");
scanf("%d", &(library.books_count));
library.bookp = (Sbook *)calloc(library.books_count,sizeof (Sbook));
fflush(stdin);
addexistingBooks(library, i);
menu(Choice);
if(strcmp(Choice,"add")==0)
{
addBook(library, i);
}
free(library.bookp);
return 0;
}
void menu(char String[30])
{
printf("Welcome to the library. If you read about heresy, prepare to be purged \n");
printf("Please choose a command, by writing the appropriate command: \n");
printf("1. Write 'add' to add a book. \n");
printf("2. Write 'remove' to remove a book. \n");
printf("3. Write 'redact' to redact a book. \n");
printf("4. Write 'Sort by criteria' to sort the books, where criteria can stand for: 1.bookname, 2.author, 3.genre, 4.price. \n");
printf("Enter your command: ");
gets(String);
}
void addexistingBooks(Slib library, int i)
{
for(i=0;i<library.books_count;i++)
{
printf("Enter the name of the book: \n");
fgets(library.bookp[i].book_name,32,stdin);
printf("Enter the genre of the book: \n");
fgets(library.bookp[i].book_genre,32,stdin);
printf("Enter the author of the book: \n");
fgets(library.bookp[i].author,32,stdin);
printf("Enter the page count of the book: \n");
scanf("%d", &(library.bookp[i].page_count));
printf("Enter the price of the book: \n");
scanf("%f", &(library.bookp[i].price));
fflush(stdin);
}
}
void addBook(Slib library, int i)
{
(library.books_count)++;
realloc(library.bookp,library.books_count);
fflush(stdin);
if(library.bookp==NULL)
{
exit(1);
}
printf("Enter the name of the book: \n");
fgets(library.bookp[i].book_name,32,stdin);
printf("Enter the genre of the book: \n");
fgets(library.bookp[i].book_genre,32,stdin);
printf("Enter the author of the book: \n");
fgets(library.bookp[i].author,32,stdin);
printf("Enter the page count of the book: \n");
scanf("%d", &(library.bookp[i].page_count));
printf("Enter the price of the book: \n");
scanf("%f", &(library.bookp[i].price));
fflush(stdin);
}
Your code contains several mistakes.
Lets start from the "non-blocking" mistakes. Those that, even if they can be really critical and have to be corrected, are not the real cause of the crash you experience.
The flush of standard input, fflush(stdin); is something that is not defined by the standard, so using it leads to undefined behavior: in some environments it could work, in some other environment it could not work, and there can be environments (the worst ones) in which it seems to work but it is actually harmful. It is recommended to avoid it.
Function gets() is dangerous because it doesn't provide any control on the size of the string inserted by the user, and its use should be avoided.
The issues in the void addBook() function
You try increasing the available space using realloc:
void *realloc(void *ptr, size_t size);
It needs the original pointer and the new size. But you pass library.books_count that is just the number of books. Meaning that, if the library used to contain 4 books, you try to allocate 5 bytes only.
You instead need to allocate library.books_count * sizeof(Sbook) bytes.
Furthermore it returns a new pointer. You need to assign it to the book pointer:
library.bookp = realloc(library.bookp, library.books_count * sizeof(Sbook));
In main() you initialize a i variable, but you never update it, since you store the numbers of books directly in library.books_count.
Then you pass it to addexistingBooks(), and it is redundant because you could use library.books_count itself for the loop, as you actually do. You can use it as the loop variable, but you don't need to have that parameter. Just
void addexistingBooks(Slib library, )
{
int i; /* If your C version is C99 or later, you can declare it in the loop itself */
for(i=0;i<library.books_count;i++)
{
/* Omissis */
}
}
Finally you pass it to addBook(), and not only it is redundant (as you can simply store the new book at index library.books_count-1, but it is actively harmful because you are always updating index 0 (because the value of parameter i is 0).
Although it is possible to pass structures to functions as values, it is not recommended. The first reason is that you will overload the stack of the process (the whole struct will be allocated in the stack area, that is quite big in PC applications but quite limited in embedded systems). The second reason will give you functional problems.
In fact, parameters passed by value are copies of the variables passed to the function. This means that any change made on them will not be reflected to original structures. In your case, the update of library.bookp pointer will not be available outside the function, causing (1) the original structure pointing to an invalid memory address location (becoming a dangling pointer), (2) the leak of the newly allocated memory, that nobody will be able to free().
Pass structures by address, instead, using pointers to structures. addBook() function, considering the i parameter removal, would become as follows
void addBook(Slib *library)
{
int i = library->books_count;
(library->books_count)++;
library->bookp = realloc(library->bookp, library->books_count * sizeof(Sbook));
/* and so on... the value of 'i' is now library->books_count-1 */
}
/* Call from main */
int main()
{
Slib library;
/* Omissis */
menu(Choice);
if(strcmp(Choice,"add")==0)
{
addBook(&library, i);
}
free(library.bookp);
return 0;
}
The definition of realloc function,
void *realloc(void *ptr, size_t size);
So, your realloc function:
realloc(library.bookp,library.books_count);
should change to:
library.bookp = realloc(library.bookp,sizeof(Sbook)*library.books_count);
OT, i see in your menu function, you use gets. It's dangerous, you should use fgets from stdin in stead. See in this link Why is the gets function so dangerous that it should not be used?
I just wanted to ask that is there any way to dynamically allocate memory to an existing array of elements at runtime in C? For example.. if i declared int arr[25]; then I would be able to take maximum of 25 integers in my array.. But what if the user wants to enter some more integers.. but we dont know in advance how many? Also I dont want to waste the memory by assigning something like int arr[500]; just to be sure that the user doesnt exceed the upper bound of my array :( I'm really confused and sad as I'm unable to find a solution for this.. Does C even support such kind of thing? If not then in which programming language would it be easier to tackle a problem like this? P.S-> I'm new to programming so I'm sorry if this is a noob question. :/
you need to do dynamic memory allocation using malloc()/realloc() and release it using free() once you are done.
int* a = malloc(25*sizeof(int));
//use a like array...a[0]...to a[24]
// realloacte if you need to grow it
a = realloc(a,50);
free(a);
The above logic should be used in C. If you are writing into C++, you should use STL std::vector<T>
if it is an array you might actually want to check out the calloc() function:
void* calloc (size_t num, size_t size);
It can be used like so:
/* calloc example */
#include <stdio.h> /* printf, scanf, NULL */
#include <stdlib.h> /* calloc, exit, free */
int main ()
{
int i,n;
int * pData;
printf ("Amount of numbers to be entered: ");
scanf ("%d",&i);
pData = (int*) calloc (i,sizeof(int));
if (pData==NULL) exit (1);
for (n=0;n<i;n++)
{
printf ("Enter number #%d: ",n+1);
scanf ("%d",&pData[n]);
}
printf ("You have entered: ");
for (n=0;n<i;n++) printf ("%d ",pData[n]);
free (pData);
return 0;
}
If you need to resize the array later look at the realloc function. (and yes it does keep the original data if succesfull)
There is a class in c++ that you may find useful, which is called a vector. You can add to the front of a vector: myVector.push_front(myElement) and to the end of a vector: myVector.push_back(myElement). If this type of functionality is very important to you, I would recommend using a c++ vector.
Alternately, you can use the malloc() function in c to request a specific amount of memory at runtime: char *five_chars = malloc(sizeof(char) * 5). Just be sure to call free(five_chars) when you're done with the memory.
I've a file which contains names and grades of students, and I'd like to write a program which can sort their grades (like midterm 1,midterm 2) according to user choice. I wrote as far as the choice part and opening the file, yet I don't know how to make program read only certain part of the file (like only Midterm 1 grades for example) and sort them only. Here's what I've wrote so far;
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int number;
char name[30];
char surname[30];
int midterm1,midterm2,midterm3;
} Student;
int main()
{
int choice,studentnumber,midterm1,midterm2,midterm3;
char surname;
FILE *cfPtr;
struct student *name;
name = malloc( 10 * sizeof(Student));
if ((cfPtr = fopen("grades.txt", "r")) == NULL)
printf("File cannot be opened.\n");
else {
const int STUDENTSMAX = 100;
Student students[STUDENTSMAX];
int i = 0;
while (!feof(cfPtr))
{
fscanf(cfPtr, "%d%s%s%d%d%d", &students[i].number, &students[i].name,&students[i].surname, &students[i].midterm1, &students[i].midterm2, &students[i].midterm3);
printf("%4d%15s%15s%10d%10d%10d\n", students[i].number, students[i].name,students[i].surname, students[i].midterm1, students[i].midterm2, students[i].midterm3);
i++;
}
printf("What would you like to do? \n"
"1- Sort according to midterm 1\n"
"2- Sort according to midterm 2\n"
"3- Sort according to midterm 3\n"
"4- Exit\n");
scanf("%d",&choice);
while (choice != 4);{
switch (choice) {
case 1:
qsort(students,10,sizeof(int),comp);
for (i=0; i<9; i++)
printf("%4d%15s%15s%10d%10d%10d\n", students[i].number, students[i].name,students[i].surname, students[i].midterm1);
fclose(cfPtr);
}
system("PAUSE");
return 0;
}
Given what might be a somewhat free form text file (based on the shown code), it probably makes sense just to read the entire file (somewhat like you are already doing) and only use the parts that you need. If the text file has a very specific format with fixed offsets, you could seek to certain locations in the file and read a specific column value, then seek to the next offset and read the column value from the next row. But that is probably more trouble than it is worth and would not be much more efficient (if at all).
Having said that, to sort the results, you probably need the entire file anyway. For example, if you just read and sort the "midterm 1" value, then the result would just be sorted grades without any associated name and student number. So without knowing more about the goal, you might consider creating a struct that can hold a single row (student number, name, surname, midterm1, etc.). Then create an array of those and read each row into an element of the array. If you know how many rows exist up front, you can allocate the array in one chunk, otherwise you might need to reallocate it as you go to grow it.
Once you have read the entire array, you could sort based on the desired value (e.g., with qsort.
Having mentioned that, there a few problems/issues with the existing shown code:
The second printf has fewer format specifiers (%s) than parameters.
The third printf with the "What would you like to do" question is missing the closing paren.
The fprintf is incorrect; it should have a file handle as the first parameter. I suspect, though, that it was maybe meant to be printf?
The final while loop has an extraneous semicolon (;) following its closing paren, which means that it has an empty body rather than the apparently intended printf and switch statement.
The switch statement is a bit odd as written. I assume that is the "unfinished" part. But including the fclose in it seems strange. It should probably be at the end of the main else.
Using system("PAUSE"); is maybe not the best choice. Perhaps using getch would make more sense to pause for input.
Edit Here is some additional information in response to your comment asking for more details. This sounds like homework to me, so it doesn't seem right just to give the answer. But here is one way to do it:
Define a struct with the 6 items that are in the file (basically put in the 6 variables that you currently have defined as local variables).
Declare a local variable (e.g., grades) as a pointer to struct that you defined.
Use malloc to allocate memory and assign it to the pointer just mentioned. The amount of memory is perhaps the trickiest part of this whole thing. The size parameter to malloc will be something like numRecs * sizeof( yourstruct ). The question is what numRecs should be. If this is an assignment and you were told how many records there would be (a maximum), then just use that. If, though, it is "unknown", then there are a couple of ways of dealing with that. One is to just guess at a number (e.g., 100) and then while reading them in a loop use realloc if you exceed 100. The other alternative (probably less efficient) would be to use two loops - read through them once without storing them but just count them and then allocate the known size and read them again. I would use the realloc version.
Replace the use of the local variables with the array (that was malloced). For example, instead of studentnumber you would use grades[arraypos].studentnumber. While you read them in, keep a counter of how many there are. You can then use qsort to sort the array.
Edit 2
Your struct definition looks correct except that the FILE *cfPtr; member should not be in it. It should still be a local variable.
For ease of use, you can define the struct as typedef struct { ... } Student;. That way you can just use Student instead of struct Student in the code. Note that I capitalized the name (personal preference in naming to make it not look like a variable name).
For the malloc, you are close. But as written, it is allocating space for a single record. You would need something like this: name = malloc( 50 * sizeof( struct student )); (or malloc( 50 * sizeof( Student )); if you change it to use the typedef. That assumes there would not be 50 or fewer records to read from the file.
I am writing a simple program in c so I can understand better the language but I have a strange problem.
As you see from the code below I have only one loop that it exits when I insert 255 as a value. The problem is that when I select the first(insert option) and after I insert a name the program starts something like a looping and gives me all the time the selection screen...
#include<stdio.h>
#include<stdlib.h>
struct student{
char *name;
int id;
};
void insertStudent(void);
struct student * init(void);
int main(){
struct student *p;
int selectionCode=0;
while(selectionCode!=255){
printf("\nInsert students:1");
printf("\nDisplay students:2");
printf("\nExit:255");
printf("\n\nEnter selection:");
scanf("%d",&selectionCode);
p=init();
switch(selectionCode){
case 1:
insertStudent();
//printf("1\n");
break;
case 2:
//printf("2\n");
break;
case 255:
break;
}
}
//p->name="stelios";
//p->id=0;
//printf("Name:%s ID:%d",p->name,p->id);
//free(p);
//p=NULL;
return 0;
}
struct student *init(void)
{
struct student *p;
p=(struct student *)malloc(sizeof(struct student));
return p;
}
void insertStudent(void){
struct student *p;
p=init();
printf("Enter Name:");
scanf("%s",p->name);//return 1;
printf("Enter ID:");
scanf("%d",&p->id);
//printf("test");
}
Part of the problem may be that the code is not allocating memory for the name field in the structure. The init function allocates a new structure but does not initialize the name field. The insertStudent function then uses scanf to read into that uninitialized pointer. That results in writing to "random" memory and can result in any number of problems including an access violation.
Looks like you have a memory leak, I would pass p into insertStudent().
You also have a return 1; in the middle of the insertStudent() call, so it will be returning before finishing its job.
You have "return 1;" after you scan in the name. It looks like logically you should not be returning at that point, since you want to enter in the ID. Also, you declared the function as returning "void" so returning one is an error.
Edit: The real problem is that you never allocated space for the name string.
try to:
struct student *insertStudent(void){
struct student *p;
p=init();
printf("Enter Name:");
scanf("%s",p->name);
printf("Enter ID:");
scanf("%d",&p->id);
//printf("test");
return p;
}
On the main
case 1:
free(p);
p=insertStudent();
//printf("1\n");
On the init you have to allocate space for the name.
What a mess... :-)
You never malloc() a buffer for p->name, but you are filling if with the scanf().
That is corrupting the memory of your program.
Besides... In your functions you are using the variable p and in your main program as well.
This is NOT the same variable, but you seem to assume it is.
Another problem: return 1; after the scanf() aborts the insertStudent() function so "enter ID " is never executed.
It is a void function so it should not return a value, by the way. The compiler has probably issued a warning about that.
There is probably more wrong with it, but this is what I spot after giving it a quick once over.
You need to remove the "return 1;" from insertStudent, otherwise is will no compile.
You should initialize p->name with malloc and change "scanf("%s",p->name);" to "scanf("%s", &p->name);", because you need a pointer to *char.