Why do I get a segmentation fault accessing a struct? - c

Edit: added the rest of my code so it's easier to see
I'm receiving a segmentation fault when trying to access certain values of a struct in a header file.
Here's courses.c:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "structs.h"
void createStudents () {
int random, i;
for (i = 0; i < 12; i++) {
students[i].firstName = firstName[i];
students[i].lastName = lastName[i];
random = 10000 + rand() % 89999;
students[i].num.studentNum = random;
printf("%d - %s, %s \n", students[i].num.studentNum, students[i].lastName, students[i].firstName);
}
}
void createCourses () {
int numbers[999];
int numbersLeft = 999;
char courseCode[512];
char courseCode1[512];
char courseCode2[512];
int numCourses = 3;
int random, i, j;
for (i = 0; i < 999; i++) {
numbers[i] = i;
}
for (j = 0; j < 1; j++) {
random = rand() % numbersLeft;
if (random < 10) {
snprintf(courseCode, sizeof courseCode, "CS00%d", random);
courses[0].cCode = courseCode;
}
else if (random < 100 && random > 9) {
snprintf(courseCode, sizeof courseCode, "CS0%d", random);
courses[0].cCode = courseCode;
}
else if (random > 99){
snprintf(courseCode, sizeof courseCode, "CS%d", random);
courses[0].cCode = courseCode;
}
courses[0].cName = courseName[0];
courses[0].cDescription = courseDescription[0];
numbers[random] = numbers[numbersLeft-1];
numbersLeft--;
random = 4 + rand() % 4;
courses[0].maxRegister = random;
}
for (j = 0; j < 1; j++) {
random = rand() % numbersLeft;
if (random < 10) {
snprintf(courseCode1, sizeof courseCode1, "CS00%d", random);
courses[1].cCode = courseCode1;
}
else if (random < 100 && random > 9) {
snprintf(courseCode1, sizeof courseCode1, "CS0%d", random);
courses[1].cCode = courseCode1;
}
else if (random > 99){
snprintf(courseCode1, sizeof courseCode1, "CS%d", random);
courses[1].cCode = courseCode1;
}
courses[1].cName = courseName[1];
courses[1].cDescription = courseDescription[1];
numbers[random] = numbers[numbersLeft-1];
numbersLeft--;
random = 4 + rand() % 4;
courses[1].maxRegister = random;
}
for (j = 0; j < 1; j++) {
random = rand() % numbersLeft;
if (random < 10) {
snprintf(courseCode2, sizeof courseCode2, "CS00%d", random);
courses[2].cCode = courseCode2;
}
else if (random < 100 && random > 9) {
snprintf(courseCode2, sizeof courseCode2, "CS0%d", random);
courses[2].cCode = courseCode2;
}
else if (random > 99){
snprintf(courseCode2, sizeof courseCode2, "CS%d", random);
courses[2].cCode = courseCode2;
}
courses[2].cName = courseName[2];
courses[2].cDescription = courseDescription[2];
numbers[random] = numbers[numbersLeft-1];
numbersLeft--;
random = 4 + rand() % 4;
courses[2].maxRegister = random;
}
}
void regiserStudents () {
int checkSum = 0, checkSum1 = 0, checkTemp = 0, count0 = 0, count1 = 0, count2 = 0;
int wCount0 = 0, wCount1 = 0, wCount2 = 0;
int v, i, j, random, max0, max1, max2;
max0 = courses[0].maxRegister;
max1 = courses[1].maxRegister;
max2 = courses[2].maxRegister;
for (i = 0; i < 2; i++) {
checkTemp = count0;
for (j = 0; j < 12; j++) {
random = rand() % 3;
if (random == 0) {
if (count0 == 0) {
courses[random].registered[count0] = &students[j];
count0++;
}
else {
checkSum1 = students[j].num.studentNum;
for (v = 0; v < checkTemp; v++) {
checkSum = courses[0].registered[v]->num.studentNum;
if (checkSum == checkSum1) {
/*Do Nothing*/
}
else if (count0 == max0) {
courses[random].waitlisted[count0] = &students[j];
wCount0++;
}
else {
courses[random].registered[count0] = &students[j];
count0++;
}
/*}*/
}
}
}
if (random == 1) {
if (count1 == 0) {
courses[random].registered[count1] = &students[j];
count1++;
}
else {
checkSum1 = students[j].num.studentNum;
for (v = 0; v < checkTemp; v++) {
checkSum = courses[1].registered[v]->num.studentNum;
if (checkSum == checkSum1) {
/*Do Nothing*/
}
else if (count1 == max1) {
courses[random].waitlisted[count1] = &students[j];
wCount1++;
}
else {
courses[random].registered[count1] = &students[j];
count1++;
}
}
}
}
if (random == 2) {
if (count2 == 0) {
courses[random].registered[count2] = &students[j];
count2++;
}
else {
checkSum1 = students[j].num.studentNum;
for (v = 0; v < checkTemp; v++) {
checkSum = courses[2].registered[v]->num.studentNum;
if (checkSum == checkSum1) {
/*Do Nothing*/
}
else if (count2 == max2) {
courses[random].waitlisted[count2] = &students[j];
wCount2++;
}
else {
courses[random].registered[count2] = &students[j];
count2++;
}
}
}
}
}
}
courses[0].studentRegistered = count0;
courses[1].studentRegistered = count1;
courses[2].studentRegistered = count2;
courses[0].studentWaitlisted = wCount0;
courses[1].studentWaitlisted = wCount1;
courses[2].studentWaitlisted = wCount2;
}
void printCourses () {
int i;
printf("\n%s - %s: %s\nRegistered Students (%d/%d):\n", courses[0].cCode, courses[0].cName, courses[0].cDescription, courses[0].studentRegistered, courses[0].maxRegister);
for (i = 0; i < courses[0].studentRegistered; i++) {
printf("* %d - %s, %s \n", courses[0].registered[i]->num.studentNum, courses[0].registered[i]->lastName, courses[0].registered[i]->firstName);
}
printf("Waitlisted Students (%d)", courses[0].studentWaitlisted);
if (courses[0].studentWaitlisted == 0) {
printf("\n");
}
else {
for (i = 0; i < courses[0].studentWaitlisted; i++) {
printf("* %d - %s, %s \n", courses[0].waitlisted[i]->num.studentNum, courses[0].waitlisted[i]->lastName, courses[0].waitlisted[i]->firstName);
}
}
printf("\n%s - %s: %s\nRegistered Students (%d/%d):\n", courses[1].cCode, courses[1].cName, courses[1].cDescription, courses[1].studentRegistered, courses[1].maxRegister);
for (i = 0; i < courses[1].studentRegistered; i++) {
printf("* %d - %s, %s \n", courses[1].registered[i]->num.studentNum, courses[1].registered[i]->lastName, courses[1].registered[i]->firstName);
}
printf("\n%s - %s: %s\nRegistered Students (%d/%d):\n", courses[2].cCode, courses[2].cName, courses[2].cDescription, courses[2].studentRegistered, courses[2].maxRegister);
for (i = 0; i < courses[2].studentRegistered; i++) {
printf("* %d - %s, %s \n", courses[2].registered[i]->num.studentNum, courses[2].registered[i]->lastName, courses[2].registered[i]->firstName);
}
}
And here's my header file
structs.h
#ifndef STRUCTS_H_
#define STRUCTS_H_
char *firstName[] = {
"Emma", "Liam", "Olivia",
"Noah", "Ava", "Logan",
"Sophia", "Lucas", "Isabella",
"Mason", "Shaylyn", "Jack"
};
char *lastName[] = {
"Smith", "Johnson", "Williams",
"Brown", "Jones", "Miller",
"Davis", "Garcia", "Rodriguez",
"Wilson", "Seguin", "Loveday"
};
typedef struct{
int studentNum;
}studentNumber;
typedef struct{
char *firstName;
char *lastName;
studentNumber num;
}studentID;
studentID students[12];
char *courseName[] = {"Web Programming", "Technical Communication", "Processor Architecture"};
char *courseDescription[] = {"Learn the language of HTML, and how to create websites.", "Learn the essentials of communication skills, and how to apply them on the job.", "Learn the basics of circuits and Machine Language coding."};
typedef struct {
int maxRegister;
char *cCode;
char *cName;
char *cDescription;
studentID *registered[8];
studentID *waitlisted[12];
int studentRegistered;
int studentWaitlisted;
}course;
course courses[3];
#endif
Printing the values of the registered students works fine, but when I print the waitlisted students I get a segmentation error. I used gdb and found it was on this line but couldn't figure out why:
printf("%d - %s, %s \n", courses[0].waitlisted[i]->num.studentNum, courses[0].waitlisted[i]->lastName, courses[0].waitlisted[i]->firstName);

studentID *waitlisted[12]; That means they will hold the address of variable of type structure studentID. You simply didn't do this but start to access those pointer variables. You have passed them to scanf which invokes undefined behavior due to trying to read an unintialized pointer variable.
So what you need to do here -
courses[i].waitlisted = malloc(sizeof *courses[i].waitlisted * courses[i].studentWaitlisted);
Same goes for the studentID also. Here fistName is a char* you need to allocate some meory to access it otherwise it's UB.
Or
typedef struct{
char firstName[100]; //you are considering that name length would be 100
//at max.
char lastName[100];
studentNumber num;
}studentID;
After OP edited question:
The seg fault you get is because of accessing a local variable after it's lifetime ended.
courses[0].cCode = courseCode;
What you can do is
courses[0].cCode = strdup(courseCode);
Initialize array int numbers[999]={0}; otherwise you might access garbage value as the indexing is result of random number geneartion.
if( random < 999){
numbers[random] = numbers[numbersLeft-1];
numbersLeft--;
}
else{
fprintf(stderr, "%s\n","Error" );
}
Lots of repeated code. You should remove repeated code. And also there is no need for single-iteration-for-loop.

Related

how to get different array in for loop every time?

#include<stdio.h>
#include<time.h>
int main(void)
{
srand(time(NULL));
int answer;
int treatment = rand() % 4;
printf("###발모제 찾기###\n\n");
int cntShowBottle = 0;
int prevCntShowBottle = 0;
int ptr[4] = { 0,0,0,0 };
int bottle[4] = { 0, 0, 0, 0 };
int isincluded = 0;
for (int i = 1; i <= 3; i++)
{
do {
cntShowBottle = rand() % 2 + 2;
} while (cntShowBottle == prevCntShowBottle);
prevCntShowBottle = cntShowBottle;
printf(" %d 번째 시도 : ", i);
for (int j = 0; j < cntShowBottle; j++)
{
int randBottle = rand() % 4;
if (bottle[randBottle] == 0)
{
bottle[randBottle] = 1;
if (randBottle == treatment)
{
isincluded = 1;
}
}
else
{
j--;
}
}
}
if (bottle[0] == ptr[0] && bottle[1] == ptr[1] && bottle[2] == ptr[2] && bottle[3] == ptr[3])
{
int bottle[4] = { 0,0,0,0 };
for (int j = 0; j < cntShowBottle; j++)
{
int randBottle = rand() % 4;
if (bottle[randBottle] == 0)
{
bottle[randBottle] = 1;
if (randBottle == treatment)
{
isincluded = 1;
}
}
else
{
j--;
}
}
}
else
{
return 0;
}
for (int i = 0; i < 4; i++)
{
ptr[i] = bottle[i];
}
for (int k = 0; k < 4; k++)
{
if (bottle[k] == 1)
printf("%d ", k + 1);
}
printf("번 물약을 머리에 바릅니다.\n\n");
if (isincluded == 1)
{
printf("성공!\n");
}
else
{
printf("실패...\n");
}
printf("\n ...계속 하려면 아무키나 누르세요...");
getchar(0);
printf("\n\n발모제는 몇 번? : ");
scanf_s("%d", &answer);
if (answer == treatment+1)
{
printf("\n 정답! \n");
}
else
{
printf("\n 실패! \n 정답은 %d 였습니다.\n", treatment+1);
}
return 0;
}
in this loop, for (int j = 0; j < cntShowBottle; j++), 'bottle' array will be [0,1,1,1] or [1,1,0,0] etc. In this loop, how to get different array without overlapping(like [0,1,1,0] and again [0,1,1,0])?? I tried comparing each elements, if it takes overlapping array, makes 'bottle' array again. but it didn't run properly. please help..

How do you properly allocate space in C

I'm writing a program in C and I'm aware you have to allocate appropriate space for efficient code but am unsure of how to start, I've written and completed my program and it would be a shame to restart. If anyone can guide me how to properly malloc space for my program it would be appreciated.
Here is my code as follows:
main.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "courses.h"
int main (int argc, char *argv[]) {
srand (time(NULL));
createStudents ();
createCourses ();
regiserStudents ();
printCourses ();
return 1;
}
courses.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include "structs.h"
void createStudents () {
int random, i;
for (i = 0; i < 12; i++) {
students[i].firstName = *firstName[i];
students[i].lastName = *lastName[i];
random = 10000 + rand() % 89999;
students[i].num.studentNum = random;
printf("%d - %s, %s \n", students[i].num.studentNum, students[i].lastName, students[i].firstName);
}
}
void createCourses () {
int numbers[999];
int numbersLeft = 999;
char courseCode[512];
int numCourses = 3;
int random, i, j;
for (i = 0; i < 999; i++) {
numbers[i] = i;
}
for (j = 0; j < numCourses; j++) {
random = rand() % numbersLeft;
if (random < 10) {
snprintf(courseCode, sizeof courseCode, "CS00%d", random);
}
else if (random < 100 && random > 9) {
snprintf(courseCode, sizeof courseCode, "CS0%d", random);
}
else {
snprintf(courseCode, sizeof courseCode, "CS%d", random);
}
courses[j].cName = courseName[j];
courses[j].cDescription = courseDescription[j];
courses[j].cCode = courseCode;
numbers[random] = numbers[numbersLeft-1];
numbersLeft--;
random = 4 + rand() % 4;
courses[j].maxRegister = random;
}
}
void regiserStudents () {
int checkSum = 0, checkSum1 = 0, checkTemp = 0, count0 = 0, count1 = 0, count2 = 0;
int v, i, j, random;
for (i = 0; i < 2; i++) {
checkTemp = count0;
for (j = 0; j < 12; j++) {
random = rand() % 3;
if (random == 0) {
if (count0 == 0) {
courses[random].registered[count0] = &students[j];
count0++;
}
else {
checkSum1 = students[j].num.studentNum;
for (v = 0; v < checkTemp; v++) {
checkSum = courses[0].registered[v]->num.studentNum;
if (checkSum == checkSum1) {
/*Do Nothing*/
}
else {
courses[random].registered[count0] = &students[j];
count0++;
}
}
}
}
if (random == 1) {
if (count1 == 0) {
courses[random].registered[count1] = &students[j];
count1++;
}
else {
checkSum1 = students[j].num.studentNum;
for (v = 0; v < checkTemp; v++) {
checkSum = courses[1].registered[v]->num.studentNum;
if (checkSum == checkSum1) {
/*Do Nothing*/
}
else {
courses[random].registered[count1] = &students[j];
count1++;
}
}
}
}
if (random == 2) {
if (count2 == 0) {
courses[random].registered[count2] = &students[j];
count2++;
}
else {
checkSum1 = students[j].num.studentNum;
for (v = 0; v < checkTemp; v++) {
checkSum = courses[2].registered[v]->num.studentNum;
if (checkSum == checkSum1) {
/*Do Nothing*/
}
else {
courses[random].registered[count2] = &students[j];
count2++;
}
}
}
}
}
}
courses[0].studentRegistered = count0;
courses[1].studentRegistered = count1;
courses[2].studentRegistered = count2;
}
void printCourses () {
int i;
printf("\n%s - %s\n%s\nRegistered Students (%d/%d):\n", courses[0].cCode, courses[0].cName, courses[0].cDescription, courses[0].studentRegistered, courses[0].maxRegister);
for (i = 0; i < courses[0].studentRegistered; i++) {
printf("%d - %s, %s \n", courses[0].registered[i]->num.studentNum, courses[0].registered[i]->lastName, courses[0].registered[i]->firstName);
}
printf("\n%s - %s\n%s\nRegistered Students (%d/%d):\n", courses[1].cCode, courses[1].cName, courses[1].cDescription, courses[1].studentRegistered, courses[1].maxRegister);
for (i = 0; i < courses[1].studentRegistered; i++) {
printf("%d - %s, %s \n", courses[1].registered[i]->num.studentNum, courses[1].registered[i]->lastName, courses[1].registered[i]->firstName);
}
printf("\n%s - %s\n%s\nRegistered Students (%d/%d):\n", courses[2].cCode, courses[2].cName, courses[2].cDescription, courses[2].studentRegistered, courses[2].maxRegister);
for (i = 0; i < courses[2].studentRegistered; i++) {
printf("%d - %s, %s \n", courses[2].registered[i]->num.studentNum, courses[2].registered[i]->lastName, courses[2].registered[i]->firstName);
}
}
courses.h
#ifndef COURSES_H_
#define COURSES_H_
void createStudents();
void createCourses ();
void regiserStudents ();
void printCourses ();
#endif
structs.h
#ifndef STRUCTS_H_
#define STRUCTS_H_
char *firstName[] = {
"Emma", "Liam", "Olivia",
"Noah", "Ava", "Logan",
"Sophia", "Lucas", "Isabella",
"Mason", "Shaylyn", "Jack"
};
char *lastName[] = {
"Smith", "Johnson", "Williams",
"Brown", "Jones", "Miller",
"Davis", "Garcia", "Rodriguez",
"Wilson", "Seguin", "Loveday"
};
typedef struct{
int studentNum;
}studentNumber;
typedef struct{
char *firstName;
char *lastName;
studentNumber num;
}studentID;
studentID students[12];
char *courseName[] = {"Web Programming", "Technical Communication", "Processor Architecture"};
char *courseDescription[] = {"Learn to make websites!", "Learn the essentials of communication skills", "Learn the basics of circuits and Machine Language coding"};
typedef struct {
int maxRegister;
char *cCode;
char *cName;
char *cDescription;
studentID *registered[8];
studentID *waitlisted[12];
int studentRegistered;
int studentWaitlisted;
}course;
course courses[3];
#endif
Essentially the program should run as: create students, create random school courses, fill the students into the courses, and then print everything while accessing the structs from a header file (structs.h)
Here's the message I receive of running the program after it compiles:
Segmentation fault (core dumped)
In createStudents(), you don't need to dereference firstName[i] nor lastName[i]:
students[i].firstName = *firstName[i];
students[i].lastName = *lastName[i];
Since firstName[i] already gives you a char *, you can assign that pointer directly to students[i].firstName (same goes for lastName):
students[i].firstName = firstName[i];
students[i].lastName = lastName[i];

Possible mode error

I've made this program that computes the mean, the median and the mode from an array. Although I've tested with some examples, I found out there might be a case that I have forgotten as for many of the inputs I've tested it works but the testing program that my teacher is using gave me an error for a certain test, but I was not presented with its input. Maybe someone can have a look and see if I am making a mistake at the mode point of the code:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void *safeMalloc(int n) {
void *p = malloc(n);
if (p == NULL) {
printf("Error: malloc(%d) failed. Out of memory?\n", n);
exit(EXIT_FAILURE);
}
return p;
}
int main(int argc, char *argv[]) {
int n, i;
scanf("%d", &n);
int *array = safeMalloc(n * sizeof(int));
for (i = 0; i < n; i++) {
int value;
scanf("%d", &value);
array[i] = value;
}
//mean
double mean;
double sum = 0;
for (i = 0; i < n; i++) {
sum = sum + (double)array[i];
}
mean = sum / n;
printf("mean: %.2f\n", mean);
//median
float temp;
int j;
for (i = 0; i < n; i++)
for (j = i + 1; j < n; j++) {
if (array[i] > array[j]) {
temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
printf("median: %d\n", array[n / 2]);
//mode
int val = array[0], noOfRepetitions = 1, valMax = array[0], maxRepetitions = 1, possibleMax = 1;
for (i = 1; i < n; i++) {
if (array[i] == val) {
noOfRepetitions++;
}
if (array[i] != val) {
val = array[i];
noOfRepetitions = 1;
}
if (noOfRepetitions == possibleMax) {
maxRepetitions = 1;
continue;
}
if (noOfRepetitions > maxRepetitions) {
valMax = val;
maxRepetitions = noOfRepetitions;
possibleMax = maxRepetitions;
}
}
if (maxRepetitions > 1) {
printf("mode: %d\n", valMax);
} else {
printf("mode: NONE\n");
}
return 0;
}
My idea for mode was because the numbers are sorted when just transverse it. If the next element is the same as the previous one, increase the noOfRepetitions. If the noOfRepetition is bigger than the maxRepetitions until now, replace with that. Also store the last maximum val needed if we have for example more than 2 numbers with the same number of repetitions.
EDIT: The mode of an array should return the number with the maximum number of occurrences in the array.If we have 2 or more number with the same number of maximum occurrences , there isn't a mode on that array.
I've discovered my mistake. I didn't think of the case when I have numbers with same maximum frequency and after that came one with lower frequency but still bigger than others. For example : 1 1 1 2 2 2 3 3 4 5 6.With my code , the result would have been 3 . I just needed to change the comparison of noOfRepetitions with oldMaxRepetition.
There seems to be no purpose for the variable possibleMax. You should just remove these lines:
if(noOfRepetitions==possibleMax){
maxRepetitions=1;
continue;
}
They cause maxRepetitions to be reset erroneously.
You could detect if the distribution is multimodal and print all mode values:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
void *safeMalloc(int n) {
void *p = malloc(n);
if (p == NULL) {
printf("Error: malloc(%d) failed. Out of memory?\n", n);
exit(EXIT_FAILURE);
}
return p;
}
int main(int argc, char *argv[]) {
int n, i;
if (scanf("%d", &n) != 1 || n <= 0)
return 1;
int *array = safeMalloc(n * sizeof(int));
for (i = 0; i < n; i++) {
if (scanf("%d", &array[i]) != 1)
return 1;
}
//mean
double sum = 0;
for (i = 0; i < n; i++) {
sum = sum + (double)array[i];
}
printf("mean: %.2f\n", sum / n);
//median
int j;
for (i = 0; i < n; i++) {
for (j = i + 1; j < n; j++) {
if (array[i] > array[j]) {
int temp = array[j];
array[j] = array[i];
array[i] = temp;
}
}
}
printf("median: %d\n", array[n / 2]);
//mode
int val = array[0], noOfRepetitions = 1, valMax = array[0], maxRepetitions = 1;
for (i = 1; i < n; i++) {
if (array[i] == val) {
noOfRepetitions++;
if (noOfRepetitions > maxRepetitions) {
valMax = val;
maxRepetitions = noOfRepetitions;
}
} else {
val = array[i];
noOfRepetitions = 1;
}
}
if (maxRepetitions == 1) {
printf("mode: NONE\n");
} else {
printf("mode: %d", valMax);
val = array[0];
noOfRepetitions = 1;
for (i = 1; i < n; i++) {
if (array[i] == val) {
noOfRepetitions++;
} else {
if (noOfRepetition == maxRepetitions && val != valMax) {
printf(", %d", val);
}
val = array[i];
noOfRepetitions = 1;
}
}
if (noOfRepetition == maxRepetitions && val != valMax) {
printf(", %d", val);
}
printf("\n");
}
return 0;
}
Your code to search a mode seems too complicated. Compare this:
//mode
int val = array[0], noOfRepetitions = 1,
valMax = array[0], maxRepetitions = 1;
for (i = 1; i < n; i++) {
if (array[i] == val) {
if (++noOfRepetitions > maxRepetitions) {
valMax = val;
maxRepetitions = noOfRepetitions;
}
}
else
{
val = array[i];
noOfRepetitions = 1;
}
}
It's probably the simplest code to do what you need, but it overwrites maxVal and maxRepetitions much too often.
The following version overwrites the two 'max' variables only once per each new maximum found – at the cost of duplicating some part of code:
//mode
int val = array[0], noOfRepetitions = 1,
valMax = array[0], maxRepetitions = 1;
for (i = 1; i < n; i++) {
if (array[i] == val) {
++noOfRepetitions;
}
else
{
if (noOfRepetitions > maxRepetitions) {
valMax = val;
maxRepetitions = noOfRepetitions;
}
val = array[i];
noOfRepetitions = 1;
}
}
if (noOfRepetitions > maxRepetitions) {
valMax = val;
maxRepetitions = noOfRepetitions;
}

Getting a segmentation fault in my code.

When trying to run my program on Linux I get a segmentation fault. I am a novice with C. In doing research, I figure the reason is probably a loop running beyond the last index in one of the arrays and accessing memory it shouldn't. Any hints?
Program overview: takes in a file in a certain format and determines from that file that best place to eat at based on the voter's three top favorites and least favorite.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int outputToFile (int winner, char **restaurantList, char **voterNameList, int numberOfVoters, int **voterFavorites) {
int index;
FILE *output;
output = fopen ("output_1", "w"); //write mode
fprintf(output, "%s\n", restaurantList[winner]); // write out the winning restuarant
fprintf(output, "Happy:\n");
for (index = 0; index < numberOfVoters ; index++) { // write out the happy persons
if (voterFavorites[index][1] == winner || voterFavorites[index][2] == winner || voterFavorites[index][3] == winner) {
fprintf(output, "%s\n", voterNameList[index]);
}
}
fprintf (output, "Sad:\n");
for (index = 0; index < numberOfVoters ; index++) { // write out the sad persons
if (voterFavorites[index][4] == winner) {
fprintf(output, "%s\n", voterNameList[index]);
}
}
fclose (output);
}
int countScore (int **voterFavorites, int tallyCard[], int numberOfVoters, int numberOfRestaurants) {
int index;
for (index = 0; index < numberOfRestaurants; index++ ) {
tallyCard[index] = 0;
}
for (index = 0; index < numberOfVoters; index++) {
if (voterFavorites[index][1] != -999) {
tallyCard[voterFavorites[index][1]] = tallyCard[voterFavorites[index][1]] + 1;
} else if (voterFavorites[index][2] != -999) {
tallyCard[voterFavorites[index][2]] = tallyCard[voterFavorites[index][2]] + 1;
} else if (voterFavorites[index][3] != -999) {
tallyCard[voterFavorites[index][3]] = tallyCard[voterFavorites[index][3]] + 1;
}
if (voterFavorites[index][4] != -999) {
tallyCard[voterFavorites[index][4]] = tallyCard[voterFavorites[index][4]] - 1;
}
}
}
int determineWinner( int tallyCard[], int maxVotes, int **voterFavorites) {
int x, y, max = 0, min = 999, maxIndex, percent;
for ( x = 0 ; x < 20 ; x++ ) {
if (tallyCard[x] > max) {
maxIndex = x;
max = tallyCard[x];
}
if (tallyCard[x] < min) {
if (tallyCard[x] != -999) {
min = tallyCard[x];
}
}
}
percent = max/maxVotes * 100;
if ( percent >= 50) {
return maxIndex;
} else {
for(x = 0; x < maxVotes ; x++) {
for (y = 0; y < 4; y++) {
if (voterFavorites[x][y] == min) {
voterFavorites[x][y] == -999;
}
}
}
return -444;
}
}
void inputFromFile (void) {
int index, numberOfRestaurants, numberOfVoters, winner;
char *nor, *nov, **restaurantList = malloc(20 * sizeof(char*));;
char **voterNameList = malloc(100 * sizeof(char*));
int **voterFavorites = (int**) calloc(100, sizeof(int*)), tallyCard[20];
int *fav1, *fav2, *fav3, *notFav;
FILE *input;
for ( index = 0; index < 100; index++ ) {
voterFavorites[index] = (int*) calloc(4, sizeof(int));
voterNameList[index] = malloc(26 * sizeof(char));
}
for ( index = 0 ; index < 20; index++ ) {
restaurantList[index] = malloc(51 * sizeof(char));
}
input = fopen ("input_1", "r"); // !!! need to check if this will give an error. Refer to slide set 2-48
if( input == NULL ) {
perror("Error while opening the file.\n");
exit(1);
}
//get names of restaurants
fgets(nor, 51, input);
numberOfRestaurants = atoi(nor); //resolve char * to int
for ( index = 0 ; index < numberOfRestaurants ; index++ ) {
fscanf(input, "%s", restaurantList[index]);
}
//get info lines and names of voters and initial values
fgets(nov, 101, input);
numberOfVoters = atoi(nov); //resolve char * to int
for ( index = 0 ; index < numberOfVoters ; index++ ) {
fscanf(input, "%s %i %i %i %i", voterNameList[index], fav1, fav2, fav3, notFav);
voterFavorites[index][1] = *fav1-1;
voterFavorites[index][2] = *fav2-1;
voterFavorites[index][3] = *fav3-1;
voterFavorites[index][4] = *notFav-1;
}
//count total score for resturants
countScore (voterFavorites, tallyCard, numberOfVoters, numberOfRestaurants);
winner = determineWinner(tallyCard, numberOfVoters, voterFavorites); // !!! probably need to look into these max votes
while (winner < 0) {
countScore(voterFavorites, tallyCard, numberOfVoters, numberOfRestaurants);
winner = determineWinner(tallyCard, numberOfVoters, voterFavorites);
}
outputToFile(winner, restaurantList, voterNameList, numberOfVoters, voterFavorites);
}
int main (void)
{
inputFromFile();
return 0;
}
I've been working on this for a while but I'm sure this could be cleaned up a bit. Sorry about that!
char *nor, *nov, **restaurantList = malloc(20 * sizeof(char*));;
/* ... */
fgets(nor, 51, input);
nor object is not initialized.

Intermittent Failure with Blackjack code

The purpose of this code is to play a simulated game of Blackjack. The 'Dealer' is automated and will deal two cards to itself and stop when it wins/busts or hits 17. Then the user draws until he/she is satisfied. Then a winner is determined.
I've run into a brick wall because the code compiles fine, but when it runs it will either work (and by work I mean not work as intended but it will run) or it will crash.
I have no idea how this can happen only some of the time and not all of the time and I need some help.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 52
#define LIMIT 21
enum faces{Ace = 0, Jack = 10, Queen, King};
char * facecheck(int d);
void shuffle( int deck[]);
int draw(int deck[SIZE]);
void printcards(int hand[], int numCards);
int dealer(int deck[]);
int player(int deck[]);
int value(int yourhand[]);
int victory(int d, int p);
int i, numCards = 1;
int top = 52;
int preValue = 0;
int count = 2;
int main()
{
int deck[SIZE], i, a;
int d, p;
char suits[4][9] =
{
"Hearts",
"Diamonds",
"Clubs",
"Spades"};
srand( time( NULL ) ) ;
for(i = 0; i<SIZE; i++)
{
deck[i] = i;
};
shuffle(deck);
d = dealer(deck);
p = player(deck);
victory(d, p);
return 0;
}
char * facecheck(int d)
{
static char * face[] =
{
"Ace",
"Jack",
"Queen",
"King" };
if(d == Ace)
return face[0];
else
{
if(d == Jack)
return face[1];
else
{
if(d == Queen)
return face[2];
else
{
if(d == King)
return face[3];
}
}
}
}
void shuffle( int deck[])
{
int i, j, temp;
for(i = 0; i < SIZE; i++)
{
j = rand() % SIZE;
temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
printf("The deck has been shuffled \n");
}
int draw(int deck[SIZE])
{
int numCards = 1;
int i;
int hand[numCards];
int card;
for(i = 0; i < numCards && top > 0; i++)
{
card = deck[top-1];
hand[i] = card;
top--;
}
return card;
}
void printcards(int hand[], int numCard)
{
char suits[4][9] =
{
"Hearts",
"Diamonds",
"Clubs",
"Spades"};
for(i = 0; i < numCard; i++)
{
int card = hand[i];
if(card%13 == 0 || card%13 == 10 || card%13 == 11 || card%13 == 12)
printf("%s ", facecheck(card%13) );
else
printf("%d ", card%13+1);
printf("of %s \n", suits[card/13]);
}
}
int dealer(int deck[])
{
int x;
int a;
int yourhand[10];
int handIndex = 0;
int cardLimit;
int dealerValue;
yourhand[handIndex] = draw(deck);
yourhand[handIndex] = draw(deck);
printf("The Dealers second card is:");
printcards(yourhand, handIndex+1);
cardLimit = value(yourhand);
do
{
if(cardLimit == LIMIT)
{
printcards(yourhand, handIndex+1);
dealerValue = cardLimit;
return dealerValue;
}
if(cardLimit > LIMIT)
{
printcards(yourhand, handIndex+1);
dealerValue = cardLimit;
return dealerValue;
}
if(cardLimit == 17)
{
printcards(yourhand, handIndex+1);
dealerValue = cardLimit;
return dealerValue;
}
if(cardLimit <= 16)
{
yourhand[handIndex] = draw(deck);
cardLimit = value(yourhand);
}
}
while(cardLimit <= LIMIT);
handIndex++;
}
int player(int deck[])
{
int x;
int a;
int yourhand[10];
int cardLimit;
int playerValue;
int handIndex = 2;
yourhand[handIndex] = draw(deck);
yourhand[handIndex] = draw(deck);
cardLimit = value(yourhand);
printf("Your hand is: /n");
printcards(yourhand, handIndex+1);
printf("%d /n" , cardLimit);
do
{
if(cardLimit == LIMIT)
{
printcards(yourhand, handIndex+1);
playerValue = cardLimit;
return playerValue;
}
if(cardLimit > LIMIT)
{
printcards(yourhand, handIndex+1);
playerValue = cardLimit;
return playerValue;
}
else
{
printf("What would you like to do: Press 1 to Hit. 2 to Stay. \n");
scanf("%d" , &x);
if(x == 1)
{
yourhand[handIndex] = draw(deck);
cardLimit == value(yourhand);
}
else
{
printf("Player choses to stay \n");
return playerValue;
}
}
}
while(cardLimit <= LIMIT);
handIndex++;
}
int value(int yourhand[])
{
int faceValue = 10;
int cardValue[count];
int aceValue = 11;
int card[count];
int value;
int curvalue;
for(i = 0; i < count; i++)
{
card[i] = yourhand[i];
}
for(i = 0; i < count; i++)
{
cardValue[i] = card[i]%13;
}
if(cardValue[0] >= 10 && cardValue[1] >= 10)
{
value = 20;
}
if(cardValue[0] < 10 && cardValue[1] < 10)
{
value = cardValue[0] + cardValue[1];
}
if(cardValue[0] >= 10 && cardValue[1] < 10)
{
value = faceValue + cardValue[1];
}
if(cardValue[0] < 10 && cardValue[1] >= 10)
{
value = faceValue + cardValue[0];
}
if(cardValue[0] == 0 && cardValue[1] == 0)
{
value = 12;
}
if(cardValue[0] == 0 && cardValue[1] >= 10)
{
value = 21;
}
if(cardValue[1] == 0 && cardValue[0] >= 10)
{
value = 21;
}
if(cardValue[0] == 0 && cardValue[1] < 10)
{
value = aceValue + cardValue[1];
}
if(cardValue[1] == 0 && cardValue[0] < 10)
{
value = aceValue + cardValue[0];
}
preValue = value;
if(count > 2)
{
if(cardValue[count] != 0)
{
value = curvalue;
value = preValue + curvalue;
}
else
{
if(cardValue[count] + preValue > LIMIT)
{
value = preValue + 1;
}
else
{
value = cardValue[count] + aceValue;
}
}
}
count++;
return value;
}
int victory(int d, int p)
{
if(d > p)
printf("Dealer Wins \n");
else
printf("Player Wins");
}
In your code
int dealer(int deck[])
{
int handIndex = 0;
int yourhand[10];
yourhand[handIndex] = draw(deck);
yourhand[handIndex] = draw(deck);
you never change handIndex, so these two assignments are to the same element (ie, the second draw overwrites the first)
cardLimit = value(yourhand);
now, having written to yourhand[0] twice, and without initialising any other elements, you call value which expects yourhand[0] and yourhand[1] to be initialised.
This should be visible under valgrind (you're reading random values from uninitialized memory).

Resources