Reputation: 278
Sorry for the long sections of code, but I am stumped and need a hand!
My specific problem is that when I use my parse method in order to call a "del" event, I get that odd character replacement going on in a line that, as far as I can tell, isn't being touched. This does not happen when I directly call the function "del." I've spent far too long poring over this code to no avail, attempting to implement a different way of tokenizing strings; you name it. I included ALL my code because I don't know where the issue is, as I am starting to think it does not lie within the function "parse."
I'll hang around and give as much information as is requested, for now I don't know what else to add.
P.S. The compiler links against the gnu windows libraries, that's where strsep comes from.
P.P.S. Only compiler warning is it whining about me not using char* buf
db.h
#define MAX_ITEMS 80
typedef struct item {
long id;
char* name;
char* desc;
float price;
} item_t;
extern char *strsep (char **restrict stringp, const char *restrict delim);
int isLong (char* str);
int isFloat (char* str);
void add (item_t* item, long id, char* name, char* desc, float price);
void del (item_t* item, long id);
void modify (item_t* item, long id, char* name, char* desc, float price);
void disp (item_t* item, long id);
void itemCopy (item_t* from, item_t* to);
void parse (item_t* item, char* buf);
int findLastElement (item_t* item);
db.c
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "db.h"
int isLong (char* str) {
if (str == NULL) {
return 0;
}
char* pEnd;
strtol (str, &pEnd, 10);
if (isalpha (*pEnd) || *pEnd == ' ') {
return 0;
} else {
return 1;
}
}
int isFloat (char* str) {
if (str == NULL) {
return 0;
}
char* pEnd;
strtod (str, &pEnd);
if (isalpha (*pEnd) || *pEnd == ' ') {
return 0;
} else {
return 1;
}
}
void add (item_t *item, long id, char* name, char* desc, float price) {
int i = 0;
while (1) {
if (item[i].id == id) {
printf ("Item \"%s\" with ID %lu already exists.\n", item[i].name, id);
break;
} else if (item[i].id == 0) {
item[i].id = id;
item[i].name = name;
item[i].desc = desc;
item[i].price = price;
break;
} else {
i++;
}
}
}
void del (item_t* item, long id) {
int i = 0;
int end = findLastElement (item);
while (1) {
if (item[i].id == id) {
item[i].id = 0;
item[i].name = "";
item[i].desc = "";
item[i].price = 0;
while (i < end) {
itemCopy (&item [i + 1], &item [i]);
i++;
}
break;
} else {
if (i == MAX_ITEMS) {
printf ("Item with ID %lu does not exist.\n", id);
break;
}
i++;
}
}
}
void modify (item_t *item, long id, char* name, char* desc, float price) {
int i = 0;
while (1) {
if (item[i].id == id) {
item[i].name = name;
item[i].desc = desc;
item[i].price = price;
break;
} else {
if (i == MAX_ITEMS) {
printf ("Item with ID %lu does not exist.\n", id);
break;
}
i++;
}
}
}
void disp (item_t* item, long id) {
int end = findLastElement (item);
printf ("\nID\tNAME\tDESCRIPTION\tPRICE\n--\t----\t-----------\t-----\n");
if (id == -1) {
for (int i = 0; i < end; i++) {
printf ("%lu\t%s\t%s\t$%2.2f\n", item[i].id, item[i].name, item[i].desc, item[i].price);
}
} else {
for (int i = 0; i < end; i++) {
if (item[i].id == id) {
printf ("%lu\t%s\t%s\t$%2.2f\n", item[i].id, item[i].name, item[i].desc, item[i].price);
break;
}
}
}
}
void itemCopy (item_t* from, item_t* to) {
to -> id = from -> id;
to -> name = from -> name;
to -> desc = from -> desc;
to -> price = from -> price;
}
void parse (item_t* item, char* str) {
char **ap, *argv[10], *inputstr = malloc (sizeof(str)), *ptr;
strcpy (inputstr, str);
memset (argv, 0, sizeof (argv));
for (ap = argv; (*ap = strsep (&inputstr, ",\n")) != NULL;) {
if (**ap != '\0') {
if (++ap >= &argv[10]) {
break;
}
}
}
if (strcmp (argv[0], "add\0") == 0) {
if (!isLong (argv[1]) || argv[1] == NULL) {
printf ("\nInvalid/Missing ID\n");
return;
} else if (argv[2] == NULL) {
printf ("\nInvalid/Missing Product Name.\n");
return;
} else if (argv[3] == NULL) {
printf ("\nInvalid/Missing Product Description.\n");
return;
} else if (!isFloat (argv[4]) || argv[4] == NULL) {
printf ("\nInvalid/Missing Price\n");
return;
} else {
add (item, strtol (argv[1], &ptr, 10), argv[2], argv[3], strtod (argv[4], &ptr));
}
} else if (strcmp (argv[0], "del\0") == 0) {
if (!isLong (argv[1]) || argv[1] == NULL) {
printf ("\nInvalid/Missing ID\n");
return;
} else {
del (item, strtol (argv[1], &ptr, 10));
}
}
}
int findLastElement (item_t* item) {
for (int i = 0; i < MAX_ITEMS; i++) {
if (item[i].id == 0) return i;
}
return -1;
}
main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include "db.h"
int main (int argc, char* argv[]) {
item_t item [MAX_ITEMS];
memset (item, 0, sizeof (item));
char* buf = malloc (255);
int exit = 0;
while (!exit) {
printf ("Adding 3 test items.\n");
add (item, 1234, "Pizza", "Tasty Pizza", 9.99F);
add (item, 5678, "Pasta", "Tasty Pasta", 19.99F);
add (item, 9012, "Ribs", "Tasty Ribs", 29.99F);
disp (item, -1);
printf ("\nDeleting Item with ID 5678.\n");
del (item, 5678);
disp (item, -1);
printf ("\nModifying item with ID 1234.\n");
modify (item, 1234, "Soup", "Tasty Soup", 4.99F);
disp (item, -1);
printf ("\nAdding another item with id 5678.");
add (item, 5678, "Pasta", "Tasty Pasta", 19.99F);
printf ("\nAdding item \"Pizza\" with the same ID as \"Soup\".\n");
add (item, 1234, "Pizza", "Tasty Pizza", 9.99F);
disp (item, -1);
printf ("\nDeleting item \"Soup\" and re-adding \"Pizza\".\n");
del (item, 1234);
add (item, 1234, "Pizza", "Tasty Pizza", 9.99F);
disp (item, -1);
printf ("\nDisplaying only the item with id 5678.\n");
disp (item, 5678);
printf ("\nAdding item \"Wings\" using the parsing function.\n");
parse (item, "add,9898,Wings,Tasty Wings,14.99\n");
disp (item, -1);
printf ("\nAttempting to Delete non-existent item with ID 9999.\n");
//del (item, 9999);
parse (item, "del,9999\n"); <--- This is the problem line
printf ("\nAttempting to Modify non-existent item with ID 9999.\n");
modify (item, 9999, "Test", "Test", 0.0F);
disp (item, -1);
exit = 1;
}
}
And finally, my output:
Adding 3 test items.
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
1234 Pizza Tasty Pizza $9.99
5678 Pasta Tasty Pasta $19.99
9012 Ribs Tasty Ribs $29.99
Deleting Item with ID 5678.
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
1234 Pizza Tasty Pizza $9.99
9012 Ribs Tasty Ribs $29.99
Modifying item with ID 1234.
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
1234 Soup Tasty Soup $4.99
9012 Ribs Tasty Ribs $29.99
Adding another item with id 5678.
Adding item "Pizza" with the same ID as "Soup".
Item "Soup" with ID 1234 already exists.
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
1234 Soup Tasty Soup $4.99
9012 Ribs Tasty Ribs $29.99
5678 Pasta Tasty Pasta $19.99
Deleting item "Soup" and re-adding "Pizza".
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
9012 Ribs Tasty Ribs $29.99
5678 Pasta Tasty Pasta $19.99
1234 Pizza Tasty Pizza $9.99
Displaying only the item with id 5678.
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
5678 Pasta Tasty Pasta $19.99
Adding item "Wings" using the parsing function.
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
9012 Ribs Tasty Ribs $29.99
5678 Pasta Tasty Pasta $19.99
1234 Pizza Tasty Pizza $9.99
9898 Wings Tasty Wings $14.99
Attempting to Delete non-existent item with ID 9999.
Item with ID 9999 does not exist.
Attempting to Modify non-existent item with ID 9999.
Item with ID 9999 does not exist.
ID NAME DESCRIPTION PRICE
-- ---- ----------- -----
9012 Ribs Tasty Ribs $29.99
5678 Pasta Tasty Pasta $19.99
1234 Pizza Tasty Pizza $9.99
9898 Win♦ Çdel $14.99 <--- THIS IS WHAT'S DOING MY HEAD IN
Thanks for your help in advance!
I really hope this doesn't end up being some trivially stupid rookie error.
Upvotes: 1
Views: 132
Reputation: 241771
I would have thought that the compiler would complain about parse taking a char*
as its second argument, since you actually provide a const char*
(i.e. a string constant). However, you actually try to copy the string, so you could have (and should have) made the prototype const char*
.
Let's focus on "try to copy". Leaving aside your obfuscated initialization, what you do is:
inputstr = malloc (sizeof(str));
strcpy(inputstr, str);
Before I go any further, I suggest you look at strdup
, which does exactly what you want, only correctly:
inputstr = strdup(str);
No fuss, no errors. But anyway,
str
is a char*
; that is, a pointer to a character. (It should have been const char*
, but it would still be a pointer to a character.) So sizeof(str)
is the size of a pointer, which is likely to be four bytes on your platform, although it might be eight. Either way, it's not close to long enough to hold the string "add,9898,Wings,Tasty Wings,14.99\n"
, so when you copy that into inputstr
, you'll end up overwriting random memory. (And probably again with the del
string).
sizeof(*str)
would be the size of a character, which is one byte. What I think you might have meant was strlen(str)
, which is the length of the string str
in bytes, but that wouldn't be right either because it leaves out the terminating NUL byte.
In short, what you wanted was the strdup
call above, which is equivalent to:
char* inputstr = malloc(strlen(str) + 1);
strcpy(inputstr, str);
Upvotes: 4