#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct STU{//Structure for transaction to make linked list
unsigned int SID;
unsigned int enteringgrade;
unsigned int year;
char University[32];
char Student[32];
struct STU *next;
}Node;
Node* addrecord(unsigned int, unsigned int, unsigned int, char*, char*, Node*);
void printrecord(Node *);
int main() {
char str[4];
Node *start = NULL;
struct STU stu;
while(strcmp(str, "END") != 0)
{
scanf("%s", str);
if (strcmp(str, "Student") == 0) {
scanf("%u %u %u %s %s", &stu.SID, &stu.enteringgrade, &stu.year, &stu.University, &stu.Student);
start = addrecord(stu.SID, stu.enteringgrade, stu.year, stu.University, stu.Student, start);
}
else if (strcmp(str, "print") == 0)
{
printf("Linked List Values: \n ");
printrecord(start);
}
}
free(start);
return 0;
}
Node * addrecord(unsigned int SID, unsigned int grade, unsigned int year, char* uni, char* Student2, Node *start) {
Node *newnode;
int i = 0, k = 0;
newnode = (Node *) malloc(sizeof(Node));
newnode-> SID = SID;
newnode-> enteringgrade = grade;
newnode-> year = year;
for(i = 0; uni[i] != '\0'; i )
{
newnode -> University[i] = uni[i];
}
for(k = 0; Student2[k] != '\0'; k )
{
newnode -> Student[k] = Student2[k];
}
newnode->next= start;
start = newnode;
return start;
}
void printrecord(Node *start) {
Node *current = start;
while ( current != NULL) {
printf("%u %u %u %s %s", current->SID, current-> enteringgrade, current-> year, current-> University, current->Student);
current = current ->next;
}
}
Input 1st IDE DevC
Student 10 99 2022 Stanford Charlie Smith print
Output 1st IDE DevC
Linked List Values:
10 99 2022 Stanford CharlieOGONSERVER=\DESKTOP-1KFBc
Input 2nd IDE - Clion
Student 10 99 2022 Stanford Charlie Smith
Output 2nd IDE - Clion
Linked List Values:
0 4096 0 ε ε
Process finished with exit code -1073741819 (0xC0000005)
Here is my confusion. I am trying to create a code that allows the user to input a student with the fields ID, Grade, Year, University(character array) and Student(character array). My main IDE is Clion while devC is another I had initally, but it has less functions. I understand the jargon being output in my first IDE as it is memory allocated by the string, but not used. I cannot understand why my second IDE won't output anything at all. Any hints or thoughts would be helpful. My only thoughts is that it is a memory issue and DevC will use different memory? Thanks!
CodePudding user response:
char str[4];
is an uninitialized buffer. The first iteration of while(strcmp(str, "END") != 0)
will invoke Undefined Behaviour by accessing the contents of str
as if it were an initialized, null-terminated string.
scanf("%s", str);
is as dangerous as gets
, as it too does not limit the amount of data read in. This can easily overflow the buffer. When using %s
, always include a maximum field width, which should be the size of the buffer being read into, minus 1 (leaving room for the null-terminating byte).
char buffer[128];
if (1 != scanf("7s", buffer)
fprintf(stderr, "Failed to read input.\n");
You can also see in the example above that the address-of operator (&
) is not needed when passing an array to a matching %s
specifier, as an array will decay to a pointer to its first element when passed to a function (char [N]
becomes char *
).
Additionally, the return value of scanf
should always be checked to make sure the expected number of conversions took place before the corresponding values are used.
/* Incorrect */
scanf("%u %u %u %s %s", &stu.SID, &stu.enteringgrade, &stu.year, &stu.University, &stu.Student);
/* Correct */
if (5 != scanf("%u%u%u1s1s", &stu.SID, &stu.enteringgrade, &stu.year, stu.University, stu.Student))
fprintf(stderr, "Something went wrong!\n");
If you are going read the values directly into a structure, you could just as easily pass a pointer to that structure to addrecord
, and copy the contents of the structure directly to the new node. You could even allocate the next node before reading input into it, to skip the copying step.
Also note, passing a pointer to the variable that points to the root node (Node **
) lets you modify its value in main
without having to rely on capturing the return value of addrecord
.
This call to free
free(start);
only releases the memory of the root node, and none of the others. This is a memory leak. The program exits right after this, so it is fairly harmless, but something to watch out for.
Your program with some changes:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct STU {
unsigned int SID;
unsigned int enteringgrade;
unsigned int year;
char University[32];
char Student[32];
struct STU *next;
} Node;
void addrecord(Node **, Node *);
void printrecord(Node *);
int main(void)
{
char str[256] = { 0 }; /* zero-initialize a generously sized buffer */
Node stu = { 0 }; /* stay consistent with types */
Node *root = NULL;
while (1)
{
printf("Enter command 'print', 'Student', or 'END': ");
/* limit input length, and check the return value always */
if (1 != scanf("%5s", str))
{
fprintf(stderr, "Failed to read command.\n");
break;
}
if (strcmp(str, "END") == 0)
break;
if (strcmp(str, "Student") == 0)
{
puts("ENTER: ID GRADE YEAR UNI STUDENT");
/* Again, limit input, check return */
if (5 != scanf("%u%u%u1s1s",
&stu.SID,
&stu.enteringgrade,
&stu.year,
stu.University,
stu.Student)) {
fprintf(stderr, "Bad format.\n");
break;
}
addrecord(&root, &stu);
}
else if (strcmp(str, "print") == 0)
{
puts("Linked List Values:");
printrecord(root);
} else
fprintf(stderr, "Invalid command.\n");
}
/* cleanup memory */
while (root)
{
Node *next = root->next;
free(root);
root = next;
}
}
void addrecord(Node **root, Node *from)
{
Node *node = malloc(sizeof *node);
if (!node)
{
perror("malloc");
return;
}
memcpy(node, from, sizeof *node);
node->next = *root;
*root = node;
}
void printrecord(Node *current)
{
while (current)
{
printf("%u %u %u %s %s\n",
current->SID,
current->enteringgrade,
current->year,
current->University,
current->Student);
current = current->next;
}
}
CodePudding user response:
Transferring comments into an answer.
As pm100 noted in a comment, if two IDEs disagree on the results of a program with the same data, it usually means that your program invokes undefined behaviour.
Looking at the code, char str[4]
is uninitialized on the first iteration of while(strcmp(str, "END") != 0)
. That's not good! It's officially 'undefined behaviour' (aka UB).
You then have scanf("%s", str); if (strcmp(str, "Student") == 0) {
— and str
is nowhere near big enough to hold "Student"
so if you enter that string, you definitely have a buffer overflow and UB. Make str
bigger. As Steve Summit suggested, make it a lot bigger. And don't use unconstrained scanf()
for security reasons — use something like:
char str[256] = "";
while(strcmp(str, "END") != 0)
{
if (scanf("%5s", str) != 1)
{
…report error and exit loop (or program)…
}
…
}
You should always check the return value from input functions such as the scanf()
family of functions. And, as pm100 also noted, with scanf()
et al, you should not place an &
in front of character arrays. These flaws are both apparent in your second scanf()
call.