Memory Leak in C and C++ Code - memory

I am trying to return a pointer from a function and use the return in a different function but I am getting memory leak.
The test code which I wrote and detected with memory leak by CPPCheck.
########################################################################
# include < stdio.h >
# include < malloc.h >
# include < string.h >
char* replace ( char* st, char* word, char *replaceWith );
int main ( void )
{
char str[] = "Hello how are ## and what are ## doing ?";
char word[]="##";
char replaceWith[]="you";
printf("%s",replace(str,word,replaceWith));
getchar();
return 0;
}
char* replace(char* st,char* word,char *replaceWith)
{
int i = 0;
char *sr,*s,*ret;
int oldlen;
int count = 0;
int newlen;
int stlen;
s=(char *)malloc(strlen(st) + 1);
strcpy(s, st);
oldlen=strlen(word);
newlen=strlen(replaceWith);
for (i = 0; s[i]! = '\0'; )
{
if( memcmp( &s[i], word, oldlen ) == 0)
{
count++;
i+=oldlen;
}
else
{
i++;
}
}
sr= (char *) malloc (i+1+count*(newlen-oldlen));
ret = (char *) malloc (i+1+count*(newlen-oldlen));
ret=sr;
while(*s)
{
if(memcmp( s, word, oldlen) == 0)
{
memcpy(sr, replaceWith, newlen);
s+ = oldlen;
sr+ = newlen;
}
else
{
*sr++ = *s++;
}
}
*sr = '\0';
return ret;
}

Try this
#include<stdio.h>
#include<malloc.h>
#include<string.h>
char* replace ( char* st, char* word, char *replaceWith );
int main ( void )
{
char str[] = "Hello how are ## and what are ## doing ?";
char word[]="##";
char replaceWith[]="you";
char * ret = replace(str,word,replaceWith);
printf("%s",ret);
free(ret); //freeing the allocated memory
getchar();
return 0;
}
char* replace(char* st,char* word,char *replaceWith)
{
int i = 0;
char *sr,*s,*ret, *temps;
int oldlen;
int count = 0;
int newlen;
int stlen;
s=(char *)malloc(strlen(st) + 1);
temps = s; // storing the address of s in a temp location
strcpy(s, st);
oldlen=strlen(word);
newlen=strlen(replaceWith);
for (i = 0; s[i]!= '\0';)
{
if( memcmp( &s[i], word, oldlen ) == 0)
{
count++;
i+=oldlen;
}
else
{
i++;
}
}
sr= (char *) malloc (i+1+count*(newlen-oldlen));
ret=sr;
while(*s)
{
if(memcmp( s, word, oldlen) == 0)
{
memcpy(sr, replaceWith, newlen);
s += oldlen;
sr += newlen;
}
else
{
*sr++ = *s++;
}
}
*sr = '\0';
free(temps); // freeing the memory allocated for s
return ret;
}

Always free same count with malloc.
free s, sr at end of replace,
use return value of replace instead of direct use on printf
and free return value (return of ret from replace) when not needed.

I have doing lots of experimenting with the memory leak and meanwhile I wrote the following code. Please comment about the pros and cons side of it.
#include <stdio.h>
#include <string.h>
#include <malloc.h>
// Prototype declaration of replaceAll function
static char* replaceAll(char *pSource, char *pWord, char*pWith);
/////////////////////////////////////////////////////////////////////////////
//
// NAME : main
//
// DESCRIPTION : Implementation of main which invokes the replaceAll
// function and displays the output
//
// PARAMETERS : void
//
// RETURNED VALUE : int
//
/////////////////////////////////////////////////////////////////////////////
int main( void )
{
char *finalString = NULL; // To save the base returned address
char srcString[] = "Hello how r you"; // Actual String
char pWord[] = "r"; // Word to be replaced
char pWith[] = "are"; // Word to be replaced with
printf("\n Before Calling the replaceAll function:");
printf("%s",srcString);
printf("\n");
finalString = replaceAll(srcString, pWord, pWith); //calling the replaceAll function
printf("\n After Calling the replaceAll function:");
// Checking if NULL is returned
if( finalString != NULL )
{
//printing the string
printf("%s", finalString);
}
else
{
printf("\n Error: Blank String returned ");
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
//
// NAME : replaceAll
//
// DESCRIPTION : Implementation of replaceAll function which replaces
// a word in given string with another word
//
// PARAMETERS : char *
//
// RETURNED VALUE : char *
//
/////////////////////////////////////////////////////////////////////////////
static char* replaceAll(char *pSource, char *pWord, char*pWith)
{
char *pSt = NULL; // Pointer to the source String to avoid modifying the pSource
char *pTarget = NULL; // Target pointer to be malloced
char *pTg = NULL; // Pointer to the target string
int count; // Counter
int nWord = strlen (pWord); // length of the word which needs to be replaced
int nWith = strlen (pWith); // length of the word with which the word needs to be replaced
static const char nullP = '\0'; // null character
int szTarget = 0;
// Assigning the base address of the pSource to a temporary and iterate through
for ( pSt = pSource, count = 0; *pSt != nullP; pSt++ )
{
// Count number of occurances of the Word in the String to calculate the length of the final string
if( memcmp( pSt, pWord, nWord ) == 0)
{
count++;
pSt += nWord-1;
}
}
// Calculate the required target Size
szTarget = strlen (pSource) + count * (nWith - nWord) + sizeof (nullP);
// Allocate memory for the target string
pTarget = (char *)malloc(szTarget);
// Check if the malloc function returns sucessfully
if ( pTarget != NULL)
{
// Copying the string with replacement
for (pTg = pTarget, pSt = pSource; *pSt != nullP; )
{
if( memcmp (pSt, pWord, nWord) == 0)
{
memcpy (pTg,pWith,nWith);
pSt += nWord;
pTg += nWith;
}
else
{
*pTg++ = *pSt++;
}
}
// Assigning NULL Character to the target string after copying
*pTg = '\0';
}
return pTarget;
}

Related

CS50 pset5 Speller [2022] - " :( program is free of memory errors"

I get error ":( program is free of memory errors valgrind tests failed; see log for more information."
Here is my code:
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// TODO: Choose number of buckets in hash table
const unsigned int N = 26;
// Hash table
node *table[N];
//Declare variables
unsigned int word_count;
unsigned int hash_value;
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO
hash_value = hash(word);
node *cursor = table[hash_value];
// Go in link list
while (cursor != 0)
{
if (strcasecmp(word, cursor->word) == 0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO: Improve this hash function
unsigned long total = 0;
for (int i = 0; i < strlen(word); i++)
{
total += tolower(word[i]);
}
return total % N;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// Open dictionary
FILE *file = fopen(dictionary, "r");
// it would be null if cant be open
if (file == NULL)
{
printf("Unable to open %s\n", dictionary);
return false;
}
// Declare variable words
char word[LENGTH + 1];
//Scan dictionary for strings up until EOF
while (fscanf(file, "%s", word) != EOF)
{
node *n = malloc(sizeof(node));
if (n == NULL)
{
return false;
}
//copy wordds into node
strcpy(n->word, word);
hash_value = hash(word);
n->next = table[hash_value];
table[hash_value] = n;
word_count++;
}
fclose(file);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
if (word_count > 0)
{
return word_count;
}
return 0;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
node *cursor = table[i];
while (cursor)
{
node *tmp = cursor;
cursor = cursor->next;
free(tmp);
}
if (cursor == NULL)
{
return true;
}
}
return false;
}
Here are the errors in valgrind check50:
program is free of memory errors valgrind tests failed; see log for more information.
Here is ERR log:
56 bytes in 1 blocks are still reachable in loss record 1 of 1: (file: dictionary.c, line: 80)
And 80th line code is:
while (fscanf(file, "%s", word) != EOF)
{
node *n = malloc(sizeof(node));
if (n == NULL)
{
return false;
}
unload will free one index and return to speller because of this if (cursor == NULL) block. The last node in an index should set cursor to NULL, so function is done. That conditional should be eliminated. There is really no condition in unload that should return false.

Access Lua coroutine from C

I have implemented a co-routine system. When I press ENTER to clear the first textbox, it calls contscript() which in turn calls lua_resume() but it doesn't continue the co-routine.
So what do I pass to lua_resume() to make the co-routine continue?
static lua_State *lua;
static int luapanic(lua_State *L)
{
allegro_exit();
const char *err = lua_tostring(L, -1);
DEBUGF("lua panic: %s\n", err);
printf("lua panic: %s\n", err);
return 0;
}
static int textbox(lua_State *L)
{
const char *str = luaL_checkstring(L, 1);
message(str);
return 1;
}
void contscript(void)
{
lua_resume(lua,NULL,0);
}
static int transfer_player(lua_State *L)
{
int x, y;
SpriteObj *p;
x = luaL_checkint(L, 1);
y = luaL_checkint(L, 2);
p = findobject(0);
setposition(p,x,y);
scrollToAndCentre(x,y);
return 1;
}
bool initscript(void)
{
lua = luaL_newstate();
lua_atpanic(lua, luapanic);
luaL_openlibs(lua);
lua_register(lua, "textbox", textbox);
lua_register(lua, "transfer_player", transfer_player);
return true;
}
Here is the script in question:
local co = coroutine.wrap(
function()
textbox("Dear me! I never knew birds could sing so\nbeautifully!")
coroutine.yield()
textbox("Text message #2")
end
)
co()

trouble with pmi handle on windows 7

I am trying to set up performance monitorint interrupt on counter overflow to collect some information. For this I created driver. I skip some part of code that are irrelevant.
driver.c
extern VOID EnableReadPmc();
extern VOID PmiHandle();
extern VOID GetIdt(IDT_INFO *idt);
extern ULONG64 GetCs();
#pragma pack(2)
typedef struct {
USHORT Limit;
ULONG64 Base;
}IDT_INFO;
#pragma pack()
typedef struct _entry {
ULONG64 Low;
ULONG64 High;
} entry;
PHYSICAL_ADDRESS lvt_perf_count_reg = {0xfee00340, 0x00000000};
PVOID map_lvt_perf_count_reg = NULL;
PHYSICAL_ADDRESS eoi_register = {0xfee000b0, 0x00000000};
PVOID map_eoi_register = NULL;
NTSTATUS IoCtlDispatch(IN PDEVICE_OBJECT pDeviceObject, IN PIRP pIrp) {
ULONG32 set_lvt_perf_count_reg = 0x000000ee;
//idt
IDT_INFO idtr;
entry *idt = NULL;
entry tmp_gate;
ULONG64 func;
ULONG64 seg;
ULONG64 int_setting;
//ovf status value
ULONG64 ovf_status;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
switch (pIrpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_INTERRUPT_SETTING_UP:
//disable pmc and clear ovf
WriteMsr(IA32_PERF_GLOBAL_CTRL, 0x00);
WriteMsr(IA32_FIXED_CTR_CTRL, 0x00);
ovf_status = ReadMsr(IA32_PERF_GLOBAL_STATUS);
WriteMsr(IA32_PERF_GLOBAL_OVF_CTRL, ovf_status);
//setting up lvt entry
map_lvt_perf_count_reg = MmMapIoSpace(lvt_perf_count_reg, 4, MmNonCached);
*(PULONG32)map_lvt_perf_count_reg = set_lvt_perf_count_reg;
map_eoi_register = MmMapIoSpace(eoi_register, 4, MmNonCached);
//setting up idt handler
idtr.Limit = 0;
idtr.Base = 0;
GetIdt(&idtr);
idt = idtr.Base;
tmp_gate.Low = 0;
tmp_gate.High = 0;
func = 0;
seg = 0;
int_setting = 0x8e00;
//p = 1 dpl = 0 type(interrupt gate) = 1110 ist = 0
seg = GetCs();
func = (ULONG64)PmiHandle;
tmp_gate.Low = func & 0x0ffff;
tmp_gate.Low = seg << 16 | tmp_gate.Low;
tmp_gate.Low = int_setting << 32 | tmp_gate.Low;
tmp_gate.Low = ((func & 0x0ffff0000) << 32) | tmp_gate.Low;
tmp_gate.High = (func & 0xffffffff00000000) >> 32;
idt[238] = tmp_gate;
MmUnmapIoSpace(map_lvt_perf_count_reg, 4);
map_lvt_perf_count_reg = NULL;
pIrp->IoStatus.Information = 0;
break;
default:
DbgPrint("Error in switch");
break;
}
status = pIrp->IoStatus.Status;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return status;
}
pmihandle.asm
public PmiHandle
extern Handle : proc
.code
PmiHandle:
call Handle
add rsp, 8
iretq
end
handle.c
#define IA32_PERF_GLOBAL_CTRL 0x38f
#define IA32_PERF_GLOBAL_STATUS 0x38e
#define IA32_PERF_GLOBAL_OVF_CTRL 0x390
extern ULONG64 ovf_status_handle;
extern PVOID map_eoi_register;
VOID Handle() {
WriteMsr(IA32_PERF_GLOBAL_CTRL, 0x00);
ovf_status_handle = ReadMsr(IA32_PERF_GLOBAL_STATUS);
WriteMsr(IA32_PERF_GLOBAL_OVF_CTRL, ovf_status_handle);
DbgPrint("INTERRUPT_INTERRUPT_INTERRUPT");
if (map_eoi_register != NULL)
*(PULONG32)map_eoi_register = 0x0;
else
DbgPrint("EOI failed");
}
main.c application with which I turn on counters
#include <stdio.h>
#include "include/msr_sampling.h"
#define FILE_DEVICE_MSR 0x8000
#define IOCTL_INTERRUPT_SETTING_UP CTL_CODE(FILE_DEVICE_MSR, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_FILE_TEST CTL_CODE(FILE_DEVICE_MSR, 0x806, METHOD_BUFFERED, FILE_ANY_ACCESS)
int main() {
SetProcForMsrCtr(); //set affinity mask for first proc
DriverOpen();
EnableReadPmc(); //enable __readpmc instruction
DWORD numberData = -1;
DeviceIoControl(hFile, IOCTL_INTERRUPT_SETTING_UP, NULL, 0, NULL, 0, &numberData, NULL);
ULONG64 value;
value = 0x000000000000000b;
WriteMsr(IA32_FIXED_CTR_CTRL, value);
value = 0xfffffffff000; //old value ffffffffc000
printf("%llu\n", __readpmc((1 << 30)));
WriteMsr(0x309, value);
printf("%llx\n", __readpmc((1 << 30)));
printf("=================================================\n");
ReadMsr(IA32_PERF_GLOBAL_CTRL, &value);
printf("%llX\n", value);
value = 0x0000000100000000;
WriteMsr(IA32_PERF_GLOBAL_CTRL, value);
printf("counter value: %llX\n", __readpmc((1 << 30)));
DriverClose();
system("pause");
return 0;
}
When I launch application my computer froze(does not respond to mouse movement and press key).
But if I generate interrupt with using assembly instuction INT it is OK.
I checked IDT and LVT entry via WinDbg they are correct.
What could be the problem?
Some informantion:
My processor is Intel Core i5-3210M. OS windows 7 x64. I do this on laptop.

Linked list exercise in C, what is wrong?

The code below does compile, but it doesn't run as it should.
I'm not sure what am I doing wrong, so would someone be willing to tell me what I did wrong and what I should have done better.
What do I need to change to make it run properly?
#include<stdio.h>
#include<stdlib.h>
typedef struct sub_Node
{
int value;
struct sub_Node *next;
}sub_Node;
typedef struct Node
{
char *name;
struct Node *next;
struct sub_Node *sub_start;
}Node;
Node *start;
void add_player(char *name)
{
Node *temp;
temp = (Node *)malloc(sizeof(Node));
temp->next = start;
temp->name = name;
temp->sub_start = (sub_Node *)malloc(sizeof(sub_Node));
temp->sub_start->next = NULL;
temp->sub_start->value = -1;
start = temp;
}
void initialize()
{
char *p;
p = "\0";
add_player(p);
}
void remove_player(char *name)
{
Node *p;
for(p = start; p!= NULL; p = p->next)
if(p->name == name)
{
p->name = p->next->name;
p->next = p->next->next;
}
}
sub_Node* add_descending(sub_Node* sub_start, int piece_value)
{
sub_Node *temp, *prev, *next;
temp = (sub_Node *)malloc(sizeof(sub_Node));
temp->value = piece_value;
temp->next = NULL;
prev = NULL;
next = sub_start;
while(next && next->value >= piece_value)
{
prev = next;
next = next->next;
}
if(!next)
{
prev->next = temp;
}
else
{
if(prev)
{
temp->next = prev->next;
prev->next = temp;
}
else
{
temp->next = sub_start;
sub_start = temp;
}
}
return sub_start;
}
void add_piece(char *name, int piece_value)
{
Node *p;
int c;
for(p = start; p!=NULL; p = p->next)
if(p->name == name)
p->sub_start = add_descending(p->sub_start, piece_value);
}
void print_pieces(char *name)
{
Node *p;
sub_Node *q;
for(p = start; p!=NULL; p = p->next)
if(p->name == name)
{
printf("The values of the owned pieces are:");
for(q = p->sub_start; q->value != -1; q = q->next)
printf(" %d", q->value);
}
}
int lose_piece(char *name)
{
Node *p;
sub_Node *q;
int aux;
for(p = start; p!=NULL; p = p->next)
if(p->name == name)
{
for(q = p->sub_start; q->next->value != -1; q = q->next) {}
aux = q->value;
q->value = q->next->value;
q->next = q->next->next;
return aux;
}
}
void print_players()
{
Node *p;
printf("The players are: ");
for(p = start; p->name != "\0"; p = p->next)
printf("%s ", p->name);
printf("\n");
}
int main()
{
initialize();
int y, value;
char name[20];
printf("Insert a digit to execute the desired task:\n"
"<0> end the program\n"
"<1> add a player, who doesn't own any piece yet\n"
"<2> remove a player and all his pieces\n"
"<3> print the name of all the players\n"
"<4> a player gets a piece\n"
"<5> a player loses the piece with the lowest value out of the ones that he has\n"
"<6> prints the pieces of a player in a descending order by value\n\n");
do
{
printf("digit: ");
scanf("%d", &y);
switch(y)
{
case 1:
printf("Insert the player's name: ");
scanf("%s", name);
add_player(name);
break;
case 2:
printf("Insert the player's name: ");
scanf("%s", name);
remove_player(name);
break;
case 3:
print_players();
break;
case 4:
printf("Insert the player's name: ");
scanf("%s", name);
printf("Insert the value of the piece: ");
scanf("%d", value);
add_piece(name, value);
break;
case 5:
printf("Insert the player's name: ");
scanf("%s", name);
printf("\nThe player loses the piece: %d\n", lose_piece(name));
break;
case 6:
printf("Insert the player's name: ");
scanf("%s", name);
print_pieces(name);
}
} while(y != 0);
return 0;
}
your two main problems where this scanf("%d", value); value should be passed by reference like this scanf("%d", &value); and the second is string comparison in c as in your code p->name != "\0" and if(p->name == name) this is wrong because actually you are making comparison between addresses of strings (where it resides in memory) not strings values. to compare strings in c you have to use strcmp and families.
Actually 3 main problems. for setting string values as you did in temp->name = name; is little bit more complicated than that. because you are assigning to temp->name a string from the stack that is volatile (the stack will be more likely invalid soon you return from the function) . in your case you have to alloc a new string by using malloc (and friends) or just by using strdup.
here is as a bonus a slightly rewrite of your program, you will find many advises and is a good starting point for how to structure your code for an easy maintenance.
still want to advise you to change members and variables to more declarative names as in sub_start and sub_Node can be PieceNode and pieces respectively.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct sub_Node
{
int value;
struct sub_Node *next;
}sub_Node;
typedef struct Node
{
char *name;
struct Node *next;
struct Node *prev; // this to make life easyer
struct sub_Node *sub_start;
}Node;
Node *start = NULL;
Node *find_player(char *name){
Node *tmp = start;
while( tmp ){
if(strcmp(tmp->name,name) == 0 )
break;
tmp = tmp->next;
}
return tmp;
}
// int to return Error Code
//
int add_player(char *name)
{
Node *temp;
if( find_player(name)) {
printf("player %s already exists\n", name);
return 1;
}
// do not cast malloc
temp = malloc(sizeof(Node));
if( !temp ){
printf ("not enough memory\n");
return 2;
}
temp->name = strdup ( name); // here was your error
temp->sub_start = NULL; // keep it simple
temp->prev = NULL;
temp->next = start;
if(start)
start->prev = temp;
start = temp;
return 0; // no error
}
void DestroyPieces(sub_Node* piece){
if( piece ) {
DestroyPieces( piece->next );
free( piece );
}
}
// as usual use int to return error code
int remove_player(char *name)
{
Node *player = find_player(name);
if ( !player ){
return 1; // player not found
}
if ( player->next ){
player->next->prev = player->prev;
}
if ( player->prev ){
player->prev->next = player->next;
}
DestroyPieces(player->sub_start);
free(player->name);
free(player);
return 0; // success
}
sub_Node* new_piece(int value){
sub_Node *temp = malloc( sizeof(sub_Node) );
if(temp){
temp->value = value;
temp->next = NULL;
}
return temp;
}
// int to return error code
// pass sub_start as pointer to pointer, as it might be updated
int add_descending(sub_Node** psub_start, int piece_value)
{
sub_Node *piece, *current, *prev = NULL;
if( !psub_start){
return 5; // this should not happen
}
current = *psub_start;
piece = new_piece( piece_value );
if( !piece ) return 1; // no mem
if(!current){
// this is the first and only one
*psub_start = piece;
return 0; // OK
}
while(current && current->value >= piece_value)
{
prev = current;
current = current->next;
}
if( prev )
prev->next = piece;
piece->next = current;
if( current == *psub_start ){
*psub_start = piece;
}
return 0 ; // OK
}
void add_piece(Node * player, int piece_value)
{
if ( !player) {
return ;
}
if(add_descending (&(player->sub_start), piece_value) == 0 )
return ; //OK
printf("an error occured while adding a piece (%d) to player '%s'\n",piece_value,player->name);
}
void print_pieces(Node *player)
{
sub_Node *q;
if( !player ){
return;
}
if( !player->sub_start ){
printf("Player '%s' has no pieces\n",player->name);
return;
}
printf("The values of the owned pieces are:");
for(q = player->sub_start; q != NULL; q = q->next)
printf(" %d", q->value);
printf("\n");
}
void lose_piece(Node *player)
{
if( !player ){
return;
}
sub_Node *q, *prev = NULL;
int aux;
if( !player->sub_start ){
printf("Player '%s' has no pieces\n",player->name);
return;
}
// i think you want drop the last one
for(q = player->sub_start; q->next != NULL ;prev = q, q = q->next) {
;
}
if(prev)
prev->next = NULL;
else
player->sub_start = NULL;
aux = q->value;
free(q);
printf("\nThe player loses the piece: %d\n", aux);
return;
}
void print_players()
{
Node *p;
if( !start ){
printf("there are no players, try to add some\n");
return;
}
printf("The players are: ");
for(p = start; p != NULL; p = p->next)
printf("%s ", p->name);
printf("\n");
}
void print_menu(void){
printf("Insert a digit to execute the desired task:\n"
"<0> end the program\n"
"<1> add a player, who doesn't own any piece yet\n"
"<2> remove a player and all his pieces\n"
"<3> print the name of all the players\n"
"<4> a player gets a piece\n"
"<5> a player loses the piece with the lowest value out of the ones that he has\n"
"<6> prints the pieces of a player in a descending order by value\n\n");
}
Node * get_player(char *name){
Node *player = find_player(name);
if(!player)
printf("Player '%s' do not exists\n",name);
return player;
}
int main()
{
// initialize(); no more needed
int y, value;
char name[20];
Node *player;
print_menu();
do
{
printf("digit: ");
scanf("%d", &y);
switch(y)
{
case 1:
printf("Insert the player's name: ");
scanf("%s", name);
add_player(name);
break;
case 2:
printf("Insert the player's name: ");
scanf("%s", name);
player = get_player(name);
if( player )
break;
case 3:
print_players();
break;
case 4:
printf("Insert the player's name: ");
scanf("%s", name);
player = get_player(name);
if( player ){
printf("Insert the value of the piece: ");
scanf("%d", &value);
add_piece(player, value);
}
break;
case 5:
printf("Insert the player's name: ");
scanf("%s", name);
player = get_player(name);
lose_piece(player);
break;
case 6:
printf("Insert the player's name: ");
scanf("%s", name);
player = get_player(name);
print_pieces(player);
}
} while(y != 0);
return 0;
}

Using fgets and strtok to read in data and create linked list

Need some help with reading in lines of data from a text file using the fgets and string tokenization commands, which will then be used to create a linked list. I've followed some examples I've found on Stack Overflow and other tutorial websites, but still cannot get the read function below to work properly in my program, it just causes it to crash. The data file has lines like this:
Zucchini, Squash, pound, 2.19, 45
Yellow, Squash, pound, 1.79, 15
Based on everything I've read, I believe I have the necessary code, but obviously I'm missing something. Also, I commented out one of the fields (the one for float price) as I'm not sure what to use to copy the float value from the data, as I cannot treat it as a string (the integer value right below it seems to let me get away with it in my compiler).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Struct for linked list node
struct produceItem
{
char produce[20];
char type[20];
char soldBy[20];
float price;
int quantityInStock;
struct produceItem *next;
};
// Function to read in data from file to
void read(struct produceItem **head)
{
struct produceItem *temp = NULL;
struct produceItem *right = NULL;
//char ch[3];
char line[50];
char *value;
FILE *data = fopen("RecitationFiveInput.txt", "r");
printf("Trying to open file RecitationFiveInput.txt\n");
if (data == NULL)
{
printf("Could not open file RecitationFiveInput.txt\n");
}
else
{
while(fgets(line, sizeof(line), data))
{
value = strtok(line, ", ");
strcpy(temp->produce, strdup(value));
value = strtok(NULL, ", ");
strcpy(temp->type, strdup(value));
value = strtok(NULL, ", ");
strcpy(temp->soldBy, strdup(value));
//value = strtok(NULL, ", ");
//strcpy(temp->price, strdup(value));
value = strtok(NULL, " \n");
strcpy(temp->quantityInStock, strdup(value));
temp->next = NULL;
if (*head == NULL)
{
*head = temp;
}
else
{
right = *head;
while(right->next != NULL)
{
right = right->next;
}
right->next = temp;
}
}
printf("Successfully opened file RecitationFiveInput.txt\n");
}
fclose(data);
return;
}
// Function to display the nodes of the linked list that contains the data from the data file
void display(struct produceItem *head)
{
int value = 1;
struct produceItem *temp = NULL;
temp = head;
printf("=============================================================================\n");
printf(" Item # Produce Type Sold By Price In Stock\n");
printf("=============================================================================\n");
if(temp == NULL)
{
return;
}
else
{
while(temp != NULL)
{
printf(" %d %s %s %s %lf %d\n", value, temp->produce, temp->type, temp->soldBy, temp->price, temp->quantityInStock);
value++;
temp = temp->next;
if(temp == NULL)
{
break;
}
}
}
return;
}
//Main function
int main()
{
int input = 0;
struct produceItem *head = NULL;
while(1)
{
printf("\nList Operations\n");
printf("=================\n");
printf("1. Stock Produce Department\n");
printf("2. Display Produce Inventory\n");
printf("3. Reverse Order of Produce Inventory\n");
printf("4. Export Produce Inventory\n");
printf("5. Exit Program\n");
printf("Enter your choice: ");
if(scanf("%d", &input) <= 0)
{
printf("Enter only an integer.\n");
exit(0);
}
else
{
switch(input)
{
case 1:
read(&head);
break;
case 2:
display(head);
break;
case 3:
//function
break;
case 4:
//function
break;
case 5:
printf("You have exited the program, Goodbye!\n");
return 0;
break;
default:
printf("Invalid option.\n");
}
}
}
return 0;
}
Never mind everyone, found the issue. The crashes were due to me not allocating memory for the temp pointer in the read me function.

Resources