MapViewOfFile offset - how to use it - c

Developing a game ("jogo" in PT),
the server can host up to 5 simultaneous games,
which the client will access via mapped memory.
So here's what I have:
Server:
#define MAX_JOGOS 5
typedef struct{
...
} sJogo;
typedef struct{
sJogo * pS;
} sGlobals;
sJogo jogo[MAX_JOGOS]; //global
sGlobals globals[MAX_JOGOS]; //global
HANDLE hMapFile; //global
int _tmain(int argc, LPTSTR argv[]) {
...
hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(sJogo)*MAX_JOGOS, szName);
//create map for all games
....
}
//called when new game is created
void createView(int index){
//create view for 1 game and store pointer
//### need to apply offset here ###
globals.pS[index] = (sJogo * )MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(sJogo);
}
//called by thread on event set
void CopyJogo(int index){
//use stored pointer to update jogo
CopyMemory((PVOID)globals[index].pS, &jogo[index], sizeof(sJogo));
}
Client:
HANDLE hMapFile; //global
sJogo * pS; //global
int _tmain(int argc, LPTSTR argv[]) {
...
hMapFile = OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, szName);
pS = (sJogo *)MapViewOfFile(cdata.hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(sJogo));
//### need respective offset here ###
}
I have tried creating a view of "sizeof(sJogo)*MAX_JOGOS" and then incrementing the pointer+=sizeof(sJogo) * index; but didn't manage to succeed, so now I turn to you, can you help me learn to use the offset?
I have searched quite persistently and found a good example here on stackoverflow but it's C++ and I couldn't adapt it.
The high-order DWORD offset would be sizeof(sJogo) correct?
But I don't know what granularity is or how to apply it to the low-order DWORD...
Can you help me?
Thank you.
EDIT:
The code below is returning when i = 1 (NULL), what am I doing wrong?
int _tmain(int argc, LPTSTR argv[]) {
....
hMapFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(sJogo)*MAX_JOGOS, szName);
if (hMapFile == NULL)
{...}
DWORD offset = 0;
for (i = 0; i < MAX_JOGOS; i++) {
if (MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, offset, sizeof(sJogo)) == NULL)
{
_tprintf(TEXT("Erro MapViewOfFile I: %d\n"), i);
CloseHandle(hMapFile);
return;
}
offset += sizeof(sJogo);
}
}
EDIT 2:
Solved the problem above, found the solution here:
https://msdn.microsoft.com/en-us/library/windows/desktop/aa366548%28v=vs.85%29.aspx
I wasn't taking into account the allocation granularity on the offset, which was causing MapViewOfFile to return NULL on the second attempt.
The link above shows a clear example on how to apply it to the offset.

The example in MSDN should fit for you.
You can find it here
Basically in the CreateFileMapping you declare the amount of memory to share, in the MapViewOfFile you create a 'viewport' on the memory. It can have dimensions equal or a smaller than the quantity requested.
This memory can now be read or write.
On the client side you can open the mapping with OpenFileMapping then you should map the quantity of memory that you want access, the size of a single structure. Then you can iterate while MapViewOfFile returns a valid address to access all elements of the array:
sJogo *pS = NULL;
DWORD ofset = 0;
while((pS= (sJogo *)MapViewOfFile(cdata.hMapFile, FILE_MAP_ALL_ACCESS, 0, offset, sizeof(sJogo)))
{
//Do something with the current element pointed by pS
offset += sizeof(sJogo);
}
Here we start at offset zero in the mapped memory, than we increment offset by the size of our structure. This moves the mapping to the next element of the array of structures.
When we exceed the number of elements the file mapping will return NULL.
This is not the most efficient way to handle file mapping, you want consider to create a super structure holding the number of entries available and the entries coded as VLA (Variable Lenght Array) at the end of structure:
typedef struct{
int nEntries; //Holds the number of entries
sJogo pS[];
} sGlobals;
sGlobals globals;

Related

Vulkan vkCreateInstance - Access violation writing location 0x0000000000000000

I am trying to write a basic program using Vulkan, but I keep getting a runtime error.
Exception thrown at 0x00007FFDC27A8DBE (vulkan-1.dll) in VulkanTest.exe: 0xC0000005: Access violation writing location 0x0000000000000000.
This seems to be a relatively common issue, resulting from a failure to initialize the arguments of the vkCreateInstance function. I have tried all of the solutions I found proposed to others, even initializing things I am fairly certain I don't need to, and I still haven't been able to solve the problem. The program is written in C using the MSVC compiler.
#include "stdio.h"
#include "SDL.h"
#include "vulkan\vulkan.h"
#include "System.h"
int main(int argc, char *argv[])
{
//Initialize SDL
if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
{
printf("Error");
}
printf("Success");
//Initialize Vulkan
VkInstance VulkanInstance;
VkApplicationInfo VulkanApplicationInfo;
VulkanApplicationInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
VulkanApplicationInfo.pNext = 0;
VulkanApplicationInfo.pApplicationName = "VulkanTest";
VulkanApplicationInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
VulkanApplicationInfo.pEngineName = "VulkanTest";
VulkanApplicationInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
VulkanApplicationInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo VulkanCreateInfo = {0,0,0,0,0,0,0,0};
VulkanCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
VulkanCreateInfo.pNext = 0;
VulkanCreateInfo.pApplicationInfo = &VulkanApplicationInfo;
VulkanCreateInfo.enabledLayerCount = 1;
VulkanCreateInfo.ppEnabledLayerNames = "VK_LAYER_KHRONOS_validation";
vkEnumerateInstanceExtensionProperties(0, VulkanCreateInfo.enabledExtensionCount,
VulkanCreateInfo.ppEnabledExtensionNames);
//Create Vulkan Instance
if(vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
{
printf("Vulkan instance was not created");
}
//Create SDL Window
SDL_Window* window;
window = SDL_CreateWindow("VulkanTest", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 0, 0, SDL_WINDOW_VULKAN || SDL_WINDOW_FULLSCREEN_DESKTOP);
SDL_Delay(10000);
return 0;
}
Are you sure the call to vkCreateInstance() is what is crashing? I have not tried to debug the code you have shown (that is your job), but just looking at the calls that the code is making, it should be the call to vkEnumerateInstanceExtensionProperties() that is crashing (if it even compiles at all!).
The 2nd parameter of vkEnumerateInstanceExtensionProperties() expects a uint32_t* pointer, but you are passing in a uint32_t value (VulkanCreateInfo.enabledExtensionCount) that has been initialized to 0. So, that would make the pPropertyCount parameter be a NULL pointer (if it even compiles).
You are passing VulkanCreateInfo.ppEnabledExtensionNames in the 3rd parameter (if that even compiles), and ppEnabledExtensionNames has been initialized to NULL. Per the documentation for vkEnumerateInstanceExtensionProperties():
If pProperties is NULL, then the number of extensions properties available is returned in pPropertyCount. Otherwise, pPropertyCount must point to a variable set by the user to the number of elements in the pProperties array, and on return the variable is overwritten with the number of structures actually written to pProperties.
Since pPropertCount is NULL, vkEnumerateInstanceExtensionProperties() has nowhere to write the property count to! That would certainly cause an Access Violation trying to write to address 0x0000000000000000.
The documentation clears states:
pPropertyCount must be a valid pointer to a uint32_t value
On top of that, your call to vkEnumerateInstanceExtensionProperties() is just logically wrong anyway, because the 3rd parameter expects a pointer to an array of VkExtensionProperties structs, but VulkanCreateInfo.ppEnabledExtensionNames is a pointer to an array of const char* UTF-8 strings instead.
In other words, you should not be using vkEnumerateInstanceExtensionProperties() to initialize criteria for the call to vkCreateInstance(). You are completely misusing vkEnumerateInstanceExtensionProperties(). You probably meant to use SDL_Vulkan_GetInstanceExtensions() instead, eg:
uint32_t ExtensionCount = 0;
if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, NULL))
{
...
}
const char **ExtensionNames = (const char **) SDL_malloc(sizeof(const char *) * ExtensionCount);
if (!ExtensionNames)
{
...
}
if (!SDL_Vulkan_GetInstanceExtensions(NULL, &ExtensionCount, ExtensionNames))
{
SDL_free(ExtensionNames);
...
}
VulkanCreateInfo.enabledExtensionCount = ExtensionCount;
VulkanCreateInfo.ppEnabledExtensionNames = ExtensionNames;
if (vkCreateInstance(&VulkanCreateInfo, 0, &VulkanInstance) != VK_SUCCESS)
{
...
}
SDL_free(ExtensionNames);
...

Two-dimensional char array too large exit code 139

Hey guys I'm attempting to read in workersinfo.txt and store it into a two-dimensional char array. The file is around 4,000,000 lines with around 100 characters per line. I want to store each file line on the array. Unfortunately, I get exit code 139(Not enough memory). I'm aware I have to use malloc() and free() but I've tried a couple of things and I haven't been able to make them work.Eventually I have to sort the array by ID number but I'm stuck on declaring the array.
The file looks something like this:
First Name, Last Name,Age, ID
Carlos,Lopez,,10568
Brad, Patterson,,20586
Zack, Morris,42,05689
This is my code so far:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE *ptr_file;
char workers[4000000][1000];
ptr_file =fopen("workersinfo.txt","r");
if (!ptr_file)
perror("Error");
int i = 0;
while (fgets(workers[i],1000, ptr_file)!=NULL){
i++;
}
int n;
for(n = 0; n < 4000000; n++)
{
printf("%s", workers[n]);
}
fclose(ptr_file);
return 0;
}
The Stack memory is limited. As you pointed out in your question, you MUST use malloc to allocate such a big (need I say HUGE) chunk of memory, as the stack cannot contain it.
you can use ulimit to review the limits of your system (usually including the stack size limit).
On my Mac, the limit is 8Mb. After running ulimit -a I get:
...
stack size (kbytes, -s) 8192
...
Or, test the limit using:
struct rlimit slim;
getrlimit(RLIMIT_STACK, &rlim);
rlim.rlim_cur // the stack limit
I truly recommend you process each database entry separately.
As mentioned in the comments, assigning the memory as static memory would, in most implementations, circumvent the stack.
Still, IMHO, allocating 400MB of memory (or 4GB, depending which part of your question I look at), is bad form unless totally required - especially for a single function.
Follow-up Q1: How to deal with each DB entry separately
I hope I'm not doing your homework or anything... but I doubt your homework would include an assignment to load 400Mb of data to the computer's memory... so... to answer the question in your comment:
The following sketch of single entry processing isn't perfect - it's limited to 1Kb of data per entry (which I thought to be more then enough for such simple data).
Also, I didn't allow for UTF-8 encoding or anything like that (I followed the assumption that English would be used).
As you can see from the code, we read each line separately and perform error checks to check that the data is valid.
To sort the file by ID, you might consider either running two lines at a time (this would be a slow sort) and sorting them, or creating a sorted node tree with the ID data and the position of the line in the file (get the position before reading the line). Once you sorted the binary tree, you can sort the data...
... The binary tree might get a bit big. did you look up sorting algorithms?
#include <stdio.h>
// assuming this is the file structure:
//
// First Name, Last Name,Age, ID
// Carlos,Lopez,,10568
// Brad, Patterson,,20586
// Zack, Morris,42,05689
//
// Then this might be your data structure per line:
struct DBEntry {
char* last_name; // a pointer to the last name
char* age; // a pointer to the name - could probably be an int
char* id; // a pointer to the ID
char first_name[1024]; // the actual buffer...
// I unified the first name and the buffer since the first name is first.
};
// each time you read only a single line, perform an error check for overflow
// and return the parsed data.
//
// return 1 on sucesss or 0 on failure.
int read_db_line(FILE* fp, struct DBEntry* line) {
if (!fgets(line->first_name, 1024, fp))
return 0;
// parse data and review for possible overflow.
// first, zero out data
int pos = 0;
line->age = NULL;
line->id = NULL;
line->last_name = NULL;
// read each byte, looking for the EOL marker and the ',' seperators
while (pos < 1024) {
if (line->first_name[pos] == ',') {
// we encountered a devider. we should handle it.
// if the ID feild's location is already known, we have an excess comma.
if (line->id) {
fprintf(stderr, "Parsing error, invalid data - too many fields.\n");
return 0;
}
// replace the comma with 0 (seperate the strings)
line->first_name[pos] = 0;
if (line->age)
line->id = line->first_name + pos + 1;
else if (line->last_name)
line->age = line->first_name + pos + 1;
else
line->last_name = line->first_name + pos + 1;
} else if (line->first_name[pos] == '\n') {
// we encountered a terminator. we should handle it.
if (line->id) {
// if we have the id string's possition (the start marker), this is a
// valid entry and we should process the data.
line->first_name[pos] = 0;
return 1;
} else {
// we reached an EOL without enough ',' seperators, this is an invalid
// line.
fprintf(stderr, "Parsing error, invalid data - not enough fields.\n");
return 0;
}
}
pos++;
}
// we ran through all the data but there was no EOL marker...
fprintf(stderr,
"Parsing error, invalid data (data overflow or data too large).\n");
return 0;
}
// the main program
int main(int argc, char const* argv[]) {
// open file
FILE* ptr_file;
ptr_file = fopen("workersinfo.txt", "r");
if (!ptr_file)
perror("File Error");
struct DBEntry line;
while (read_db_line(ptr_file, &line)) {
// do what you want with the data... print it?
printf(
"First name:\t%s\n"
"Last name:\t%s\n"
"Age:\t\t%s\n"
"ID:\t\t%s\n"
"--------\n",
line.first_name, line.last_name, line.age, line.id);
}
// close file
fclose(ptr_file);
return 0;
}
Followup Q2: Sorting array for 400MB-4GB of data
IMHO, 400MB is already touching on the issues related to big data. For example, implementing a bubble sort on your database should be agonizing as far as performance goes (unless it's a single time task, where performance might not matter).
Creating an Array of DBEntry objects will eventually get you a larger memory foot-print then the actual data..
This will not be the optimal way to sort large data.
The correct approach will depend on your sorting algorithm. Wikipedia has a decent primer on sorting algorythms.
Since we are handling a large amount of data, there are a few things to consider:
It would make sense to partition the work, so different threads/processes sort a different section of the data.
We will need to minimize IO to the hard drive (as it will slow the sorting significantly and prevent parallel processing on the same machine/disk).
One possible approach is to create a heap for a heap sort, but only storing a priority value and storing the original position in the file.
Another option would probably be to employ a divide and conquer algorithm, such as quicksort, again, only sorting a computed sort value and the entry's position in the original file.
Either way, writing a decent sorting method will be a complicated task, probably involving threading, forking, tempfiles or other techniques.
Here's a simplified demo code... it is far from optimized, but it demonstrates the idea of the binary sort-tree that holds the sorting value and the position of the data in the file.
Be aware that using this code will be both relatively slow (although not that slow) and memory intensive...
On the other hand, it will require about 24 bytes per entry. For 4 million entries, it's 96MB, somewhat better then 400Mb and definitely better then the 4GB.
#include <stdlib.h>
#include <stdio.h>
// assuming this is the file structure:
//
// First Name, Last Name,Age, ID
// Carlos,Lopez,,10568
// Brad, Patterson,,20586
// Zack, Morris,42,05689
//
// Then this might be your data structure per line:
struct DBEntry {
char* last_name; // a pointer to the last name
char* age; // a pointer to the name - could probably be an int
char* id; // a pointer to the ID
char first_name[1024]; // the actual buffer...
// I unified the first name and the buffer since the first name is first.
};
// this might be a sorting node for a sorted bin-tree:
struct SortNode {
struct SortNode* next; // a pointer to the next node
fpos_t position; // the DB entry's position in the file
long value; // The computed sorting value
}* top_sorting_node = NULL;
// this function will free all the memory used by the global Sorting tree
void clear_sort_heap(void) {
struct SortNode* node;
// as long as there is a first node...
while ((node = top_sorting_node)) {
// step forward.
top_sorting_node = top_sorting_node->next;
// free the original first node's memory
free(node);
}
}
// each time you read only a single line, perform an error check for overflow
// and return the parsed data.
//
// return 0 on sucesss or 1 on failure.
int read_db_line(FILE* fp, struct DBEntry* line) {
if (!fgets(line->first_name, 1024, fp))
return -1;
// parse data and review for possible overflow.
// first, zero out data
int pos = 0;
line->age = NULL;
line->id = NULL;
line->last_name = NULL;
// read each byte, looking for the EOL marker and the ',' seperators
while (pos < 1024) {
if (line->first_name[pos] == ',') {
// we encountered a devider. we should handle it.
// if the ID feild's location is already known, we have an excess comma.
if (line->id) {
fprintf(stderr, "Parsing error, invalid data - too many fields.\n");
clear_sort_heap();
exit(2);
}
// replace the comma with 0 (seperate the strings)
line->first_name[pos] = 0;
if (line->age)
line->id = line->first_name + pos + 1;
else if (line->last_name)
line->age = line->first_name + pos + 1;
else
line->last_name = line->first_name + pos + 1;
} else if (line->first_name[pos] == '\n') {
// we encountered a terminator. we should handle it.
if (line->id) {
// if we have the id string's possition (the start marker), this is a
// valid entry and we should process the data.
line->first_name[pos] = 0;
return 0;
} else {
// we reached an EOL without enough ',' seperators, this is an invalid
// line.
fprintf(stderr, "Parsing error, invalid data - not enough fields.\n");
clear_sort_heap();
exit(1);
}
}
pos++;
}
// we ran through all the data but there was no EOL marker...
fprintf(stderr,
"Parsing error, invalid data (data overflow or data too large).\n");
return 0;
}
// read and sort a single line from the database.
// return 0 if there was no data to sort. return 1 if data was read and sorted.
int sort_line(FILE* fp) {
// allocate the memory for the node - use calloc for zero-out data
struct SortNode* node = calloc(sizeof(*node), 1);
// store the position on file
fgetpos(fp, &node->position);
// use a stack allocated DBEntry for processing
struct DBEntry line;
// check that the read succeeded (read_db_line will return -1 on error)
if (read_db_line(fp, &line)) {
// free the node's memory
free(node);
// return no data (0)
return 0;
}
// compute sorting value - I'll assume all IDs are numbers up to long size.
sscanf(line.id, "%ld", &node->value);
// heap sort?
// This is a questionable sort algorythm... or a questionable implementation.
// Also, I'll be using pointers to pointers, so it might be a headache to read
// (it's a headache to write, too...) ;-)
struct SortNode** tmp = &top_sorting_node;
// move up the list until we encounter something we're smaller then us,
// OR untill the list is finished.
while (*tmp && (*tmp)->value <= node->value)
tmp = &((*tmp)->next);
// update the node's `next` value.
node->next = *tmp;
// inject the new node into the tree at the position we found
*tmp = node;
// return 1 (data was read and sorted)
return 1;
}
// writes the next line in the sorting
int write_line(FILE* to, FILE* from) {
struct SortNode* node = top_sorting_node;
if (!node) // are we done? top_sorting_node == NULL ?
return 0; // return 0 - no data to write
// step top_sorting_node forward
top_sorting_node = top_sorting_node->next;
// read data from one file to the other
fsetpos(from, &node->position);
char* buffer = NULL;
ssize_t length;
size_t buff_size = 0;
length = getline(&buffer, &buff_size, from);
if (length <= 0) {
perror("Line Copy Error - Couldn't read data");
return 0;
}
fwrite(buffer, 1, length, to);
free(buffer); // getline allocates memory that we're incharge of freeing.
return 1;
}
// the main program
int main(int argc, char const* argv[]) {
// open file
FILE *fp_read, *fp_write;
fp_read = fopen("workersinfo.txt", "r");
fp_write = fopen("sorted_workersinfo.txt", "w+");
if (!fp_read) {
perror("File Error");
goto cleanup;
}
if (!fp_write) {
perror("File Error");
goto cleanup;
}
printf("\nSorting");
while (sort_line(fp_read))
printf(".");
// write all sorted data to a new file
printf("\n\nWriting sorted data");
while (write_line(fp_write, fp_read))
printf(".");
// clean up - close files and make sure the sorting tree is cleared
cleanup:
printf("\n");
fclose(fp_read);
fclose(fp_write);
clear_sort_heap();
return 0;
}

GetFileSizeEx fails for file mapping

Im having trouble creating a named shared memory and inspecting its size. The function GetFileSizeEx fails when I call it in a function like this. Any ideas on how to debug this?
void test_getsize(const char* lpName, int size){
HANDLE handle = CreateFileMapping(
INVALID_HANDLE_VALUE, // use paging file
NULL, // default security
PAGE_READWRITE, // read/write access
0, // maximum object size (high-order DWORD)
size, // maximum object size (low-order DWORD)
lpName); // name of mapping object
if (handle== NULL || handle== INVALID_HANDLE_VALUE){
last_error = get_error_from_errorno();
*error_return =1;
}
LARGE_INTEGER new_size;
err = GetFileSizeEx(handle, &new_size);
if (err==0){ printf("err ");} else {printf("pass ");}
printf("size=%lu\n", (unsigned long)new_size.QuadPart);
}
The handle you pass to GetFileSizeEx must be a handle to a file. You are passing it a handle to a file mapping, which is a completely different thing, so it won't work.
Since apparently you want the size of the file mapping (called a section object), and I don't think the Win32 API provides this feature, you would need to use the native Windows API called NtQuerySection. Here's an idea of how it might work (I haven't tried it):
typedef enum _SECTION_INFORMATION_CLASS
{
SectionBasicInformation,
SectionImageInformation
} SECTION_INFORMATION_CLASS;
typedef struct _SECTION_BASIC_INFORMATION {
PVOID Base;
ULONG Attributes;
LARGE_INTEGER Size;
} SECTION_BASIC_INFORMATION;
typedef DWORD (WINAPI* NTQUERYSECTION)
(HANDLE, SECTION_INFORMATION_CLASS, PVOID, ULONG, PULONG);
NTQUERYSECTION NtQuerySection =
(NTQUERYSECTION)GetProcAddress(LoadLibrary("ntdll.dll"), "NtQuerySection");
SECTION_BASIC_INFORMATION SectionInfo = { 0 };
NTSTATUS = NtQuerySection(handle, SectionBasicInformation, &SectionInfo,
sizeof(SectionInfo), 0);

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);

Personal malloc function that uses a data structure to handle memory

I have this function that will take in a number of bytes to allocate and send back only if it is available and the size of the requested number of bytes fit into my small managed memory.
My question:
The appropriate data structure is not being allocated for and I'm afraid I will not get back correct addresses. Does anyone know how I can test this function using it as a library in another program?
THE DATA STRUCTURE
typedef struct memBlock{
struct memBlock* next;
unsigned long size; // Size of this block
unsigned int is_used; // bool 0 = not used 1 = used
} memBlock;
THE MALLOC FUNCTION:
char *mm_alloc(unsigned long no_of_chars){
if (!has_initialized) {
printf("No Memory has been intialized, PLEASE INITIALIZE THE MEMORY BEFORE calling This function\n");
exit(1);
}
void *cur_location; // this is where we are currentl in our memory pool
memBlock *current_loc_mb; // the current mem block location
char *mem_location; // mem location we will return to the user
/* We are going to have to include the size of our data struct when we are searching for open memory*/
no_of_chars = no_of_chars + sizeof(struct memBlock);
mem_location = 0; // set to 0 until a proper size has been found
cur_location = managed_memory_start; // start at the beginning of our allocated memory
// go until there is no more memory left, allocate until we get to the end of our managed memory
while (managed_memory_start != NULL) {
/*cur_location and cur_loc_mcb are at the same address initially,
but we use the current location as a pointer to move around our managed memory*/
cur_loc_mcb = (memBlock *)cur_location;
// if our current location is not used
if (!cur_loc_mcb->is_used) {
if (cur_loc_mcb->size >= no_of_chars) {
// we have found a size big enough or equal to what the user asks for
cur_loc_mcb->is_used = 1;
mem_location = cur_location;
break;
}
}
// at this point we dont have a size big enough, move to the next one
cur_location = cur_location + cur_loc_mcb->size;
}
/*Move the memory past or MCB and return*/
mem_location = mem_location + sizeof(struct memBlock);
return mem_location;
}
Somewhere in your code you set mem_location
mem_location = cur_location;
and later, just before returning its value, you change it
mem_location = mem_location + sizeof(struct memBlock);
it doesn't seem right ...

Resources