C - segmentation fault using struct member values - c

I'm running head-long into a segmentation fault that I'm not sure of the reason behind.
Short story... I store file names into members of a struct, then use those members to open files to load their data into linked lists. This is working fine when I only have two file, but when I go to add a third, I get a segmentation fault opening the first file.
Code will hopefully illustrate better...
int main(int argc, char* argv[])
{
/* Initalise tennisStore struct */
TennisStoreType *ts;
systemInit(ts);
/* Variables */
ts->stockFile = "stock.csv";
ts->custFile = "customer.csv";
ts->salesFile = "sales.csv";
/* Load data from files */
loadData(ts, ts->custFile, ts->stockFile);
...
}
The struct details for ts...
typedef struct tennisStore
{
CustomerNodePtr headCust;
unsigned customerCount;
StockNodePtr headStock;
unsigned stockCount;
char *custFile;
char *stockFile;
char *salesFile;
} TennisStoreType;
systemInit() seems pretty innocuous, but here's the code just in case...
void systemInit(TennisStoreType *ts)
{
/* Set ts options to be ready */
ts->headCust = NULL;
ts->headStock = NULL;
ts->customerCount = 0;
ts->stockCount = 0;
}
loadData()...
void loadData(TennisStoreType* ts, char* customerFile, char* stockFile)
{
/* Load customer data */
addCustNode(ts, customerFile);
/* Load stock data */
addStockNode(ts, stockFile);
}
Here's where the problem occurs...
void addStockNode(TennisStoreType* ts, char* stockFile)
{
/* Variables */
StockNodePtr head, new, current, previous;
unsigned stkLevel;
char *stkTok1, *stkTok2, *stkTok3, *stkTok4;
char buf[BUFSIZ];
float stkPrice;
FILE *stream;
/* Set head */
head = NULL;
/* Open stock file */
stream = fopen(stockFile, "r"); <-- segmentation fault when sales.csv line included
assert(stream);
while (fgets(buf, BUFSIZ, stream))
{
...
}
...
}
As above, when the ts->salesFile = "sales.csv" line is included in main, the segmentation fault occurs. When it isn't, all is fine (file opens, I can read from it, write to it etc). Cannot for the life of me understand why, so I'm appealing to your good nature and superior knowledge of C for potential causes of this problem.
Thanks!

ts is uninitialized, and used as is, in systemInit().
It should be malloc()ed..

change
TennisStoreType *ts;
to
TennisStoreType *ts=malloc(sizeof(TennisStoreType));
or
change
TennisStoreType *ts;
systemInit(ts);
to
TennisStoreType ts;
systemInit(&ts);

You never actually created your TennisStoreType object.
int main(int argc, char* argv[])
{
TennisStoreType *ts; // <-- allocates 4 bytes for a pointer
systemInit(ts); // <-- pass the pointer to nowhere around.
Try inserting ts = malloc(sizeof(TennisStoreType)) in between those two lines.

Related

Deleting resources

I'm a beginner in C. I currently have a task to create a program having multiple queues. How should i correct this? From my understanding, is supposed to clear all of the queues that where created. As currently i think i have memory leaks.
#include <stdio.h> //printf etc
#include <stdlib.h> //malloc calloc realloc free
#include <stdint.h>
/* number of message queues */
#define MSGQS_LEN 5
/* number of nodes in the message queue */
#define CAPACITY 5
typedef struct _node {
const char* message;
struct _node* next;
} node_t;
typedef struct {
char qName;
node_t *front, *rear;
} msg_queue_t;
typedef struct {
msg_queue_t **queues;
} MsgQs_t;
Your code has several problems.
if(msg_queues < 0)
exit(EXIT_FAILURE);
This test is not correct, msg_queues will be NULL if malloc failed for some reason, the test should read.
if(msg_queues == NULL)
exit(EXIT_FAILURE);
/* Relinquishes all resources currently held by a MsgQs_t.
The pointer to the MsgQs_t in question is set to NULL. */
MsgQs_t* unloadMsgQs(){
MsgQs_t *msg_queues;
msg_queues = NULL;
return(msg_queues);
}
You allocate a variable on the stack, initialize it to NULL and return NULL from this function.
What you actually want to do is pass a MsqQs_t* to unloadMsgQs and use this pointer as an argument to free, something like this
void unloadMsgQs(MsgQs_t *msg_q) {
if(msg_q) {
free(msg_q);
}
}
If you want to set the msg_q pointer to NULL so that it can't be reused anymore, you should probably do something like.
void unloadMsgQs(MsgQs_t **msg_q) {
if(msg_q && *msg_q) {
free(*msg_q);
*msg_q = NULL;
}
}
From what I see, my advice would be to read some more books / tutorials on programming with C and pointers in general, because it seems you don't quite grasp the basics yet (which is nothing to be ashamed of of course!)
You have to call free with the pointer value returned from malloc. For this you have to pass the pointer to unloadMsgQs as an argument.
If this function is supposed to set the pointer to NULL in the caller, you have to pass the address of the pointer.
Note that malloc's return value to indicate an error is NULL not a value < 0.
/* Returns a pointer to MsgQs_t structure and through which multiple message queues can be subsequently created.
Each individual message queue is to be identified by a unique identifier. */
MsgQs_t* initializeMsgQs(){
MsgQs_t* msg_queues;
msg_queues = malloc(sizeof(MsgQs_t));
if(msg_queues == NULL)
exit(EXIT_FAILURE);
return(msg_queues);
}
/* Relinquishes all resources currently held by a MsgQs_t.
The pointer to the MsgQs_t in question is set to NULL. */
void unloadMsgQs(MsgQs_t **msg_queues){
if(msg_queues != NULL)
{
free(*msg_queues);
*msg_queues = NULL;
}
}
/* sample use in main() */
int main(int argc, char **argv)
{
MsgQs_t* msg_queues;
msg_queues = initializeMsgQs();
/* ... */
unloadMsgQs(&msg_queues);
return 0;
}

Loading from file to linked list

I am trying to load an unknown amount of data from a file in to a linked list
Load Function
void load(FILE *file, Node **head) // while feof somewhere
{
char tempArtist[30]={'\0'}, tempAlbum[30]={'\0'}, tempTitle[30]={'\0'}, tempGenre[30]={'\0'},tempSpace='\0';
char tempPlay[100]={'\0'}, tempRating[6]={'\0'}, tempMins[8]={'\0'}, tempSecs[8]={'\0'};
Data *temp;
temp=(Data*)malloc(sizeof(Data));
while(!feof(file))
{
fscanf(file,"%s",tempArtist);
fscanf(file,"%s",tempAlbum);
fscanf(file,"%s",tempTitle);
fscanf(file,"%s",tempGenre);
fscanf(file,"%s",tempMins);
fscanf(file,"%s",tempSecs);
fscanf(file,"%s",tempPlay);
fscanf(file,"%s",tempRating);
temp->mins=strdup(tempMins);
temp->secs=strdup(tempSecs);
temp->album=strdup(tempAlbum);
temp->artist=strdup(tempArtist);
temp->genre=strdup(tempGenre);
temp->song=strdup(tempTitle);
temp->played=strdup(tempPlay);
temp->rating=strdup(tempRating);
insertFront(head,temp);
}
}
The problem I am having is that when I go to print out the list all the entries are the same as the last one read from the file. This is something to do with the strdup() but I can't get it to copy to the data type without getting access violations.
What is another method(proper method) that I could use to copy the strings read from the file and pass them to the insert?
InsertFront
void insertFront(Node **head, Data *data)
{
Node *temp=makeNode(data);
if ((*head) == NULL)
{
*head=temp;
}
else
{
temp->pNext=*head;
*head=temp;
}
}
Data struct
typedef struct data
{
char *artist;
char *album;
char *song;
char *genre;
char *played;
char *rating;
char *mins;
char *secs;
}Data;
testing file
snoop
heartbeat
swiggity
rap
03
10
25
4
hoodie
cakeboy
birthday
hiphop
02
53
12
5
You use the same instance of temp for all your lines. The allocation should go inside the loop, ideally after you have established that the whole entry was read in successfully.
By the way, feof is not a good way to control input loops. You should check the return value of fscanf instead.
while (1) {
if (fscanf(file,"%s",tempAlbum) < 1 ) break;
if (fscanf(file,"%s",tempArtist) < 1) break;
// ...
temp = (Data *) malloc(sizeof(Data));
temp->album=strdup(tempAlbum);
temp->artist=strdup(tempArtist);
// ...
insertFront(head, temp);
}
Note how the allocation of a new node happens only after a whole record was read.
There are other ways to improve the code. For example you have very short buffers for the strings that contain numerical data. What if there is a line slip-up and you read a longer line into into such a short buffer? Also, your input seems to be line-wise, so it might be good to use fgets instead of fscan(f, "%s"), which will only read "words" and will have problems with lines that have spaces.
while(!eof) is wrong. You can do like.
for (;;) {
ret = fscanf()
if(ret == EOF) break;
}

error with own struct in c

defined in 'commando.h'
typedef struct {
int pid; /* Prozess ID */
char* name; /* Prozess Name (Programm) */
char* status; /* Status des Programms */
int check; /* bereits abgerufen? 1 - abgerufen, 0 - nicht abgerufen */
} Pstatus;
Pstatus erzeugeProzess (int neuID, char* neuName, char* neuStatus);
used in 'commando.c'
Pstatus erzeugeProzess (int neuID, char* neuName, char* neuStatus){
Pstatus erzeuge = reserviere(sizeof(struct Pstatus));
erzeuge->pid = neuID;
erzeuge->name = neuName;
erzeuge->status = neuStatus;
erzeuge->check = 0;
return erzeuge;
}
while compiling the compiler says: it's an invalid usage of an uncompleted type
and an invalid argumenttype for the erzeuge->pid ... erzeuge->check
don't know whats the Problem
anybody who can explain what I've done wrong?
first, the definition of the struct as you defined it is deprecated.
Especially using the keyword 'typedef'
which is effectively unavailable in C++, (amongst other reasons).
A much better definition of the struct is:
struct Pstatus
{
int pid; /* Prozess ID */
char* name; /* Prozess Name (Programm) */
char* status; /* Status des Programms */
int check; /* bereits abgerufen? 1 - abgerufen, 0 - nicht abgerufen */
};
then your code must reference the struct as 'struct Pstatus'.
then your code would be:
The prototype:
struct Pstatus* erzeugeProzess (int neuID, char* neuName, char* neuStatus);
The declaration:
struct Pstatus* erzeugeProzess (int neuID, char* neuName, char* neuStatus)
{
Pstatus* erzeuge = reserviere(sizeof(struct Pstatus));
if( NULL != erzeuge )
{
erzeuge->pid = neuID;
erzeuge->name = neuName;
erzeuge->status = neuStatus;
erzeuge->check = 0;
}
else
{
perror( "reserviere, %s", strerror(errno) );
}
return( erzeuge );
}
Regarding an earlier comment.
Although the stack parameters go away, by that time, the pointer to the reserved area
is already passed back to the caller.
By using a pointer in the function prototype and declaration, only a pointer
needs to be passed back, not the whole structure memory.
Also, be sure the caller checks for a NULL return value.
Also, be sure the caller performs something like free(...) to avoid a memory leak
A couple of things. One: you are allocating space for a pointer even though you are not declaring one. You want to use Pstatus *erzeuge instead. Second, you have already typedefed your struct; you no longer need to use struct Pstatus to refer to it. You want sizeof(Pstatus). In short, change your first line to:
Pstatus *erzeuge = malloc(sizeof(Pstatus));
and your code will work. Here is an ideone example as well: http://ideone.com/kHiyBg
Also, you are return statement should read:
return *erzeuge;
The alternative is to forgo pointers altogether (which it looks like is what you should be doing anyways):
Pstatus erzeuge;
erzeuge.pid = neuID;
erzeuge.name = ...;

External Functions and Parameter Size Limitation (C)

I am very much stuck in the following issue. Any help is very much appreciated!
Basically I have a program wich contains an array of structs and I am getting a segmentation error when I call an external function. The error only happens when I have more than 170 items on the array being passed.
Nothing on the function is processed. The program stops exactly when accessing the function.
Is there a limit for the size of the parameters that are passed to external functions?
Main.c
struct ratingObj {
int uid;
int mid;
double rating;
};
void *FunctionLib; /* Handle to shared lib file */
void (*Function)(); /* Pointer to loaded routine */
const char *dlError; /* Pointer to error string */
int main( int argc, char * argv[]){
// ... some code ...
asprintf(&query, "select mid, rating "
"from %s "
"where uid=%d "
"order by rand()", itable, uid);
if (mysql_query(conn2, query)) {
fprintf(stderr, "%s\n", mysql_error(conn2));
exit(1);
}
res2 = mysql_store_result(conn2);
int movieCount = mysql_num_rows(res2);
// withhold is a variable that defines a percentage of the entries
// to be used for calculations (generally 20%)
int listSize = round((movieCount * ((double)withhold/100)));
struct ratingObj moviesToRate[listSize];
int mvCount = 0;
int count =0;
while ((row2 = mysql_fetch_row(res2)) != NULL){
if(count<(movieCount-listSize)){
// adds to another table
}else{
moviesToRate[mvCount].uid = uid;
moviesToRate[mvCount].mid = atoi(row2[0]);
moviesToRate[mvCount].rating = 0.0;
mvCount++;
}
count++;
}
// ... more code ...
FunctionLib = dlopen("library.so", RTLD_LAZY);
dlError = dlerror();
if( dlError ) exit(1);
Function = dlsym( FunctionLib, "getResults");
dlError = dlerror();
(*Function)( moviesToRate, listSize );
// .. more code
}
library.c
struct ratingObj {
int uid;
int mid;
double rating;
};
typedef struct ratingObj ratingObj;
void getResults(struct ratingObj *moviesToRate, int listSize);
void getResults(struct ratingObj *moviesToRate, int listSize){
// ... more code
}
You are likely blowing up the stack. Move the array to outside of the function, i.e. from auto to static land.
Another option is that the // ... more code - array gets populated... part is corrupting the stack.
Edit 0:
After you posted more code - you are using C99 variable sized array on the stack - Bad IdeaTM. Think what happens when your data set grows to thousands, or millions, of records. Switch to dynamic memory allocation, see malloc(3).
You don't show us what listsize is, but I suppose it is a variable and not a constant.
What you are using are variable length arrays, VLA. These are a bit dangerous if they are too large since they usually allocated on the stack.
To work around that you can allocate such a beast dynamically
struct ratingObj (*movies)[listSize] = malloc(sizeof(*movies));
// ...
free(movies);
You'd then have in mind though that movies then is a pointer to array, so you have to reference with one * more than before.
Another, more classical C version would be
struct ratingObj * movies = malloc(sizeof(*movies)*listsize);
// ...
free(movies);

Ignore "initialization from incompatible pointer type" warnings?

Is there a compiler directive in order to ignore the "initialization from incompatible pointer type" warnings in Hardware_MouseDrivers_GPM_Methods and Hardware_MouseDrivers_DevInput_Methods? Turning off warnings globally is not an option though.
#include <stdio.h>
/* Mouse driver interface */
typedef struct _Hardware_MouseDriver {
int (*open)(void*, char *);
int (*close)(void*);
int (*poll)(void*);
} Hardware_MouseDriver;
/* GPM */
typedef struct _Hardware_MouseDrivers_GPM {
char *path;
} Hardware_MouseDrivers_GPM;
static int Hardware_MouseDrivers_GPM_Open(Hardware_MouseDrivers_GPM *this, char *path);
static int Hardware_MouseDrivers_GPM_Close(Hardware_MouseDrivers_GPM *this);
static int Hardware_MouseDrivers_GPM_Poll(Hardware_MouseDrivers_GPM *this);
static int Hardware_MouseDrivers_GPM_Open(Hardware_MouseDrivers_GPM *this, char *path) {
printf("GPM: Opening %s...\n", path);
this->path = path;
}
static int Hardware_MouseDrivers_GPM_Close(Hardware_MouseDrivers_GPM *this) {
printf("GPM: Closing %s...\n", this->path);
}
static int Hardware_MouseDrivers_GPM_Poll(Hardware_MouseDrivers_GPM *this) {
printf("GPM: Polling %s...\n", this->path);
}
Hardware_MouseDriver Hardware_MouseDrivers_GPM_Methods = {
.open = Hardware_MouseDrivers_GPM_Open,
.close = Hardware_MouseDrivers_GPM_Close,
.poll = Hardware_MouseDrivers_GPM_Poll
};
/* DevInput */
typedef struct _Hardware_MouseDrivers_DevInput {
char *path;
} Hardware_MouseDrivers_DevInput;
static int Hardware_MouseDrivers_DevInput_Open(Hardware_MouseDrivers_DevInput *this, char *path);
static int Hardware_MouseDrivers_DevInput_Close(Hardware_MouseDrivers_DevInput *this);
static int Hardware_MouseDrivers_DevInput_Poll(Hardware_MouseDrivers_DevInput *this);
static int Hardware_MouseDrivers_DevInput_Open(Hardware_MouseDrivers_DevInput *this, char *path) {
printf("DevInput: Opening %s...\n", path);
this->path = path;
}
static int Hardware_MouseDrivers_DevInput_Close(Hardware_MouseDrivers_DevInput *this) {
printf("DevInput: Closing %s...\n", this->path);
}
static int Hardware_MouseDrivers_DevInput_Poll(Hardware_MouseDrivers_DevInput *this) {
printf("DevInput: Polling %s...\n", this->path);
}
Hardware_MouseDriver Hardware_MouseDrivers_DevInput_Methods = {
.open = Hardware_MouseDrivers_DevInput_Open,
.close = Hardware_MouseDrivers_DevInput_Close,
.poll = Hardware_MouseDrivers_DevInput_Poll
};
/* Test drivers */
void TestDriver(Hardware_MouseDriver driver, void *data) {
/* Access the driver using a generic interface
* (Hardware_MouseDriver) */
driver.poll(data);
}
void main() {
Hardware_MouseDrivers_GPM gpm;
Hardware_MouseDrivers_DevInput devinput;
Hardware_MouseDrivers_GPM_Open(&gpm, "/dev/gpmctl");
Hardware_MouseDrivers_DevInput_Open(&devinput, "/dev/input/mice");
TestDriver(Hardware_MouseDrivers_GPM_Methods, &gpm);
TestDriver(Hardware_MouseDrivers_DevInput_Methods, &devinput);
Hardware_MouseDrivers_GPM_Close(&gpm);
Hardware_MouseDrivers_DevInput_Close(&devinput);
}
Cast the assignments to the proper types (function pointers with void * rather than your instance pointer):
.open= (int (*)(void*, char *))Hardware_MouseDrivers_GPM_Open;
Or make a type and use it in the definition and initialization of the struct:
typedef int (*openfcnt_t)(void*, char *);
typedef struct _Hardware_MouseDriver {
openfnct_t open;
} Hardware_MouseDriver;
and then
.open= (openfnct_t)Hardware_MouseDrivers_GPM_Open;
EDIT:
Upon further thought the easiest and least fiddly way for a C program will be:
.open= (void *)Hardware_MouseDrivers_GPM_Open;
I guess the obvious answer to this is the question "why not fix the code to use the right pointer type"?
EDIT:
OK, I can understand that you don't want to complicate the code unnecessarily, but I don't think it's that much of a complication, or even an unneccessary one.
Let's look at the field open in the struct Hardware_MouseDriver, which is supposed to be a pointer to a function that takes a pointer to void as its first argument.
To initialize this field, you use a pointer to the function Hardware_MouseDrivers_GPM_Open, and at another place a pointer to the function Hardware_MouseDrivers_DevInput_Open. None of these take a pointer to void as their first argument, and this is of course what the compiler warns about.
Now, if a void pointer is the same size as these pointers, and there are no other surprising differences between how they are stored and handled, calls to these functions through the open pointer will work as expected. It is likely that it will, and I guess that with this type of low-level code it is unlikely that someone will port it to TOPS-20 or something. But there is no guarantee that it
will work, and it looks (to me) strange. (And to the compiler, obviously!)
So my suggestion would be to change code like this:
static int Hardware_MouseDrivers_GPM_Open(Hardware_MouseDrivers_GPM *this, char *path) {
printf("GPM: Opening %s...\n", path);
this->path = path;
}
to the just slightly more complicated:
static int Hardware_MouseDrivers_GPM_Open(void *arg1, char *path) {
Hardware_MouseDrivers_GPM *this = arg1;
printf("GPM: Opening %s...\n", path);
this->path = path;
}
I think this change would be easier and less complicated than (1) turning off the warnings, (2) documenting it so readers can understand why that warning isn't supposed to be important here, (3) documenting it some more so your readers actually believe that you know what you are doing, and (4) handling the problems that will occur if someone actually does port your code to TOPS-20.
I had this problem and after careful examination, I decided that I should not have gotten this message. Similar lines in the structure did not generate this error.
Using (void *) function_name fixed it.
This saved me from having to examine the gcc tree.

Resources