Hello all,

I have a program that creates an array of structs. It is consistently exhibiting 1 of 2 problems and I can't figure out exactly what is wrong, but the problems seem related to each other.

Problem 1: For some reason the category member of the mediaItem struct fails to get assigned a value. Everytime I run the program, call the add function using the prompts, then call the list function -- all of the members display their value except category (which displays "null"). This is confusing because the other integer shows up fine and it is assigned using the same function.

Problem 2: Sometimes after adding an item, the program crashes with a segmentation fault when I call the list function, and it crashes on the line where it would display the category member of the mediaItem struct.

The program will usually exhibit one problem or the other if only 1 struct is in the array; if multiple structs are in the array it may produce both problems (showing null for the first item's category then crashing with a segmentation fault right before printing the second item's category).

Could someone look at my code and let me know what I'm doing wrong here? since it is a segmentation fault I am assuming I an not allocating memory correctly somehow, but I'm at a loss.

Thanks

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HLIMIT 120
#define MLIMIT 50
#define LLIMIT 6
#define DATE_SIZE 18
#define OPTIONS 4
#define NUM_CATS 7

//Media Map
//Author: KM
//
//Project 1

typedef struct mediaItem_ {
	char doc[DATE_SIZE]; //date of creation
	int  size;
	char desc[MLIMIT];
	int category;
	char location[HLIMIT];
	char creator[MLIMIT];
} mediaItem;

mediaItem *items = NULL;
int	num_items = 0;
int num_allocated = 0;
char *catArray[] ={"OS", "APP", "FILM", "MUSIC", "MUSIC VIDEO", "VIDEO GAME", "OTHER"};


//helper functions
//----------------

//void bad_selection(char *input); //declaration
void bad_selection(char *value){
	if(value[0] == '\n')
        printf("No selection detected. Please try again.\n");
	else
		printf("\n\'%s\' is not a valid response. Please try again.\n", value);
}

// addItems is an adaptation of the AddToArray function
// found at http://fydo.net/gamedev/dynamic-arrays
int addItems (mediaItem item){
	if(num_items == num_allocated){
		if(num_allocated == 0)
			num_allocated = 8;
		else
			num_allocated += num_allocated/2;

		void *_tmp = realloc(items, (num_allocated * sizeof(mediaItem)));

		//error case
		if(!_tmp){
			fprintf(stderr,
				"ERROR: Unable to allocate more memory for additonal items\n");
			return(-1);
		}

		//success case
		items = (mediaItem*)_tmp;
	}
	items[num_items++] = item;

	return num_items;
}

int remItems(int itemNum){
	if(num_items == 0 || itemNum >= num_items || itemNum < 0)
		return -1;
	if(itemNum < num_items -1){
		int i = itemNum;
		for(;i < num_items; ++i){
			if(i < num_items - 1)
				items[i] = items[i+1];
		}
	}
	return --num_items;
}

void intro(){
    printf("Hello and welcome to Media Map\n\n");
}

void bye(){
    printf("\nThank you for using Media Map!\n\n");
}

void show_menu(){
    printf("\nPlease select from the following choices:\n");
    printf("1. List Media\n");
    printf("2. Add Media\n");
    printf("3. Delete Media\n");
    printf("4. Exit\n");
}

void show_cats(){
	int i;
	printf("Choose number matching the category of the media\n");
	for(i = 0; i < NUM_CATS; ++i)
		printf("%d = %s\n", i, catArray[i]);
}

char* getString(char *string, int length){
	fgets(string, length, stdin);
	if (string[strlen(string) - 1] == '\n')
		string[strlen(string) - 1] = '\0';
}

//set val < 0 to allow user to enter arbitrary positive int value
//set val = 0 to constrain user input to available OPTIONS
//set val = NUM_CATS to constrain user input to available categories 
int getInt(int val){
	int  length = (val < 0 ? LLIMIT + 2: 3);
	int  num = -1;
	char *input;
	do{
		if(val >= 0){
			if(val > 0) show_cats();
			else show_menu();
		}
		input = (char *) malloc(length);
		getline(&input, &length, stdin);
		if (input[strlen(input) - 1] == '\n')
			input[strlen(input) - 1] = '\0';

		if(sscanf(input, "%d", &num) == 1){
			if(val > 0){
				if(num >= val || num < 0)
					bad_selection(input);
			} else if(val == 0) {
				if(num > OPTIONS || num < 1)
					bad_selection(input);
			}
		} else {bad_selection(input);}
	} while (val > 0 ? (num < 0 || num >= val) :
			(val == 0 ? (num > OPTIONS || num < 1) : num < 0));
	return num;
}


//selection functions
//-------------------

void list(){
	printf("\nList Selected\n\n");
	printf("########## LIST START ##########\n");

	int i;
	if(num_items == 0)
		printf("There are no media items to list\n");
	else {	
		for(i=0; i < num_items; ++i){
			if(i == num_items){ break; }

			mediaItem temp = items[i];
			printf("***** START RECORD %d *****\n", i);

			printf("Descript:    %s\n", temp.desc);
			printf("Location:    %s\n", temp.location);
			printf("Creator:     %s\n", temp.creator);
			printf("Category:    %s\n", temp.category);
			printf("Size:        %dMB\n", temp.size);
			printf("Created:     %s\n", temp.doc);

			printf("*****  END RECORD %d  *****\n", i);
		}
	}
	printf("##########  LIST END  ##########\n");
}

void add(){
	mediaItem *item;
	
	if((item = (mediaItem *) malloc(sizeof(mediaItem))) == NULL){
		printf("ERROR ALLOCATING MEMORY FOR NEW ITEM\n");
		exit;
	}
	
	printf("\nAdd Selected\n\n");

	printf("Enter the description of the media\n");
	getString(item->desc, HLIMIT);
	
	printf("Enter the location of the media\n");
	getString(item->location, MLIMIT);
	
	printf("Enter a creator for the media\n");
	getString(item->creator, MLIMIT);
	
	printf("Enter the size of the media (in MB)\n");
	item->size = -1;
	do{
		item->size = getInt(-1);
		if(item->size < 0)
			printf("Size must be entered as an integer. Please try again.\n");
	} while(item->size < 0);

	printf("Enter the creation time of the media\n");
	printf("YYYY/MM/DD HH:MM): ");
	getString(item->doc, DATE_SIZE);
	
	//get category info
	item->category =  getInt(NUM_CATS);
	
	printf("\n");
	
	addItems(*item);
	free(item);
}

void del(){
	int itemNum, result;
    printf("\nDelete Selected\n\n");
	printf("Enter the number of the item you wish to remove\n");
	itemNum = getInt(-1);
	if(remItems(itemNum) < 0)
		printf("Invalid index selected.\n");
	else
		printf("Item deleted.\n");

	printf("\n");
}

void exit_func(){
    printf("\nExit Selected\n");
	free(items);
}

//program
//-------

int main(){
    int selection = 0;
	
    while(selection != OPTIONS){
		selection = getInt(0);
		switch(selection){
			case 1:
				list(); break;
			case 2:
				add(); break;
			case 3:
				del(); break;
			case OPTIONS:
				exit_func(); break;
			default:
				printf("If you're seeing this, something went wrong!"); break;
		}
	}

	bye();

	return 0;
}

Edited 6 Years Ago by klactose: n/a

You need to post 255 lines of code to ask a question about an array of structures?

Edited 6 Years Ago by gerard4143: n/a

You need to post 255 lines of code to ask a question about an array of structures?

I am sorry if I offended/annoyed you, but I don't know enough about C programming to determine exactly which pieces of the code are the problem. So instead of posting a bunch of snippets that may not have anything to do with the reason the program isn't working, I thought it might be easier for seasoned C programmers to spot the problem.

I did point out the two main functions that I am calling to produce the error: add and list. I was hoping that armed with that knowledge someone would be able to follow the trail to the real culprit.

To prevent people from having to skim through 255 lines though, list starts at line 145 and add starts at line 172. Unfortunately, I don't think the problem is actually IN those functions -- although something that I have omitted may be at fault.

Thanks for any help anyone can offer.

Edited 6 Years Ago by klactose: n/a

Not sure why this thread is marked as solved, because I still can't figure out why I'm having the problems.

I can't get the posted code to build (so I therefore don't have much to say about its runtime behavior), and I'm too lazy to try to fix it. Here are some warnings you might want to look into:

main.c: In function `getString':
main.c:108: warning: no return statement in function returning non-void
main.c: In function `getInt':
main.c:123: warning: implicit declaration of function `getline'
main.c: In function `list':
main.c:162: warning: format argument is not a pointer (arg 2)
main.c: In function `del':
main.c:213: warning: unused variable `result'
main.c: In function `getString':
main.c:108: warning: control reaches end of non-void function
main.c: In function `add':
main.c:177: warning: statement with no effect
Linking...
Debug/main.o: In function `getInt':
D:/projects/misc/c/main.c:123: undefined reference to `_getline'
collect2: ld returned 1 exit status
*** Errors occurred during this build ***

[edit]One of them seems related to your Problem #1.

In general, compiling cleanly will be a good thing, so try to clean 'em all up.

Edited 6 Years Ago by Dave Sinkula: n/a

I can't get the posted code to build (so I therefore don't have much to say about its runtime behavior), and I'm too lazy to try to fix it. Here are some warnings you might want to look into:

[edit]One of them seems related to your Problem #1.

In general, compiling cleanly will be a good thing, so try to clean 'em all up.

Thanks soo much for the reply Dave. It's strange but I didn't get any of those warnings when I compiled! The problem turned out to be so simple too.

Line 162 was the problem. It should have been:

printf("Category:    %s\n", catArray[temp.category]);

You had many minor errors/warnings in your code but the culprit was a print function on line 151 where you had %s instead of %d...

/*#define _GNU_SOURCE*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define HLIMIT 120
#define MLIMIT 50
#define LLIMIT 6
#define DATE_SIZE 18
#define OPTIONS 4
#define NUM_CATS 7


typedef struct mediaItem_ {
	char doc[DATE_SIZE];
	int  size;
	char desc[MLIMIT];
	int category;
	char location[HLIMIT];
	char creator[MLIMIT];
} mediaItem;

mediaItem *items = NULL;
int	num_items = 0;
int num_allocated = 0;
char *catArray[] ={"OS", "APP", "FILM", "MUSIC", "MUSIC VIDEO", "VIDEO GAME", "OTHER"};


void bad_selection(char *value){
	if(value[0] == '\n')
        printf("No selection detected. Please try again.\n");
	else
		printf("\n\'%s\' is not a valid response. Please try again.\n", value);
}

int addItems (mediaItem item){
	if(num_items == num_allocated)
	{
		void *_tmp;
		if(num_allocated == 0)
			num_allocated = 8;
		else
			num_allocated += num_allocated/2;

		_tmp = realloc(items, (num_allocated * sizeof(mediaItem)));

		if(!_tmp){
			fprintf(stderr,
				"ERROR: Unable to allocate more memory for additonal items\n");
			return(-1);
		}

		items = (mediaItem*)_tmp;
	}
	items[num_items++] = item;

	return num_items;
}

int remItems(int itemNum){
	if(num_items == 0 || itemNum >= num_items || itemNum < 0)
		return -1;
	if(itemNum < num_items -1){
		int i = itemNum;
		for(;i < num_items; ++i){
			if(i < num_items - 1)
				items[i] = items[i+1];
		}
	}
	return --num_items;
}

void intro(){
    printf("Hello and welcome to Media Map\n\n");
}

void bye(){
    printf("\nThank you for using Media Map!\n\n");
}

void show_menu(){
    printf("\nPlease select from the following choices:\n");
    printf("1. List Media\n");
    printf("2. Add Media\n");
    printf("3. Delete Media\n");
    printf("4. Exit\n");
}

void show_cats(){
	int i;
	printf("Choose number matching the category of the media\n");
	for(i = 0; i < NUM_CATS; ++i)
		printf("%d = %s\n", i, catArray[i]);
}

char* getString(char *string, int length){
	fgets(string, length, stdin);
	if (string[strlen(string) - 1] == '\n')
		string[strlen(string) - 1] = '\0';
	return string;
}

int getInt(int val){
	int  length = (val < 0 ? LLIMIT + 2: 3);
	int  num = -1;
	char *input;
	do{
		if(val >= 0){
			if(val > 0) show_cats();
			else show_menu();
		}
		input = (char *) malloc(length);
		getline(&input, (size_t*)&length, stdin);
		if (input[strlen(input) - 1] == '\n')
			input[strlen(input) - 1] = '\0';

		if(sscanf(input, "%d", &num) == 1){
			if(val > 0){
				if(num >= val || num < 0)
					bad_selection(input);
			} else if(val == 0) {
				if(num > OPTIONS || num < 1)
					bad_selection(input);
			}
		} else {bad_selection(input);}
	} while (val > 0 ? (num < 0 || num >= val) :
			(val == 0 ? (num > OPTIONS || num < 1) : num < 0));
	return num;
}


void list()
{
	int i;
	printf("\nList Selected\n\n");
	printf("########## LIST START ##########\n");

	
	if(num_items == 0)
		printf("There are no media items to list\n");
	else {	
		for(i=0; i < num_items; ++i){
			mediaItem temp;
			if(i == num_items){ break; }

			temp = items[i];
			printf("***** START RECORD %d *****\n", i);

			printf("Descript:    %s\n", temp.desc);
			printf("Location:    %s\n", temp.location);
			printf("Creator:     %s\n", temp.creator);
			printf("Category:    %d\n", temp.category);/*this was the culprit*/
			printf("Size:        %dMB\n", temp.size);
			printf("Created:     %s\n", temp.doc);

			printf("*****  END RECORD %d  *****\n", i);
		}
	}
	printf("##########  LIST END  ##########\n");
}

void add(){
	mediaItem *item;
	
	if((item = (mediaItem *) malloc(sizeof(mediaItem))) == NULL){
		printf("ERROR ALLOCATING MEMORY FOR NEW ITEM\n");
		exit(1);
	}
	
	printf("\nAdd Selected\n\n");

	printf("Enter the description of the media\n");
	getString(item->desc, HLIMIT);
	
	printf("Enter the location of the media\n");
	getString(item->location, MLIMIT);
	
	printf("Enter a creator for the media\n");
	getString(item->creator, MLIMIT);
	
	printf("Enter the size of the media (in MB)\n");
	item->size = -1;
	do{
		item->size = getInt(-1);
		if(item->size < 0)
			printf("Size must be entered as an integer. Please try again.\n");
	} while(item->size < 0);

	printf("Enter the creation time of the media\n");
	printf("YYYY/MM/DD HH:MM): ");
	getString(item->doc, DATE_SIZE);
	

	item->category =  getInt(NUM_CATS);
	
	printf("\n");
	
	addItems(*item);
	free(item);
}

void del(){
	int itemNum;
    printf("\nDelete Selected\n\n");
	printf("Enter the number of the item you wish to remove\n");
	itemNum = getInt(-1);
	if(remItems(itemNum) < 0)
		printf("Invalid index selected.\n");
	else
		printf("Item deleted.\n");

	printf("\n");
}

void exit_func(){
    printf("\nExit Selected\n");
	free(items);
}



int main(){
    int selection = 0;
	
    while(selection != OPTIONS){
		selection = getInt(0);
		switch(selection){
			case 1:
				list(); break;
			case 2:
				add(); break;
			case 3:
				del(); break;
			case OPTIONS:
				exit_func(); break;
			default:
				printf("If you're seeing this, something went wrong!"); break;
		}
	}

	bye();

	return 0;
}

Edited 6 Years Ago by gerard4143: n/a

Yeah that line was the conflict but it was actually because I forgot to use the value as an index in the catArray that I defined earlier.

But I am still perplexed why everyone else's compilers are throwing warnings but my school's isn't... I would have caught this 5 hours ago! I suppose my school is running an older version of gcc or something.th

Edited 6 Years Ago by klactose: typo

Yeah that line was the conflict but it was actually because I forgot to use the value as an index in the catArray that I defined earlier.

But I am still perplexed why everyone else's compilers are throwing warnings but my school's isn't... I would have caught this 5 hours ago! I suppose my school is running an older version of gcc or something.th

If your using gcc try:

gcc filename.c -Wall -asni -pedantic-errors -o filename

Edited 6 Years Ago by gerard4143: n/a

This question has already been answered. Start a new discussion instead.