I'm struggling to figure out how the jsmn library works. Here is my current code and what it produces. My problem is based only in the derefBy function
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "jsmnutil.h"
char * jsmnTypes[] = {"undefined","object","array","string","primitive"};
const jsmnmarker_t jsmnErrorMarker = {NULL,-1};
jsmnmarker_t
makeMarker(jsmndata_t * data) {
jsmnmarker_t marker;
marker.data = data;
marker.index = 0;
return marker;
}
int
areEqualMarkers(jsmnmarker_t marker1, jsmnmarker_t marker2) {
return marker1.data == marker2.data && marker1.index == marker2.index;
}
int
isErrorMarker(jsmnmarker_t marker) {
return areEqualMarkers(marker,jsmnErrorMarker);
}
jsmnmarker_t
objectDeref(jsmnmarker_t marker, char * key) {
if (marker.index == -1) return marker;
int childCnt = TOKEN_SIZE(marker);
jsmnmarker_t child = marker;
child.index++;
while (childCnt > 0) {
if (TOKEN_PARENT(child) == marker.index) {
if (strncmp(TOKEN_ADDR(child),key,TOKEN_LENGTH(child)) == 0) {
child.index++;
return child;
}
childCnt--;
}
child.index++;
}
return jsmnErrorMarker;
}
jsmnmarker_t
arrayDeref(jsmnmarker_t marker, int index) {
if (marker.index == -1) return marker;
int childCnt = TOKEN_SIZE(marker);
if (index >= childCnt) return jsmnErrorMarker;
jsmnmarker_t child = marker;
child.index++;
while (1) {
if (TOKEN_PARENT(child) == marker.index) {
if (index == 0) {
return child;
}
index--;
}
child.index++;
}
return jsmnErrorMarker;
}
jsmnmarker_t
derefBy(jsmnmarker_t marker, char * fmt, ...) {
va_list ap;
char * s;
int d;
jsmnmarker_t holder = marker;
va_start(ap,fmt);
while (*fmt) {
switch(*fmt++) {
case 's':
s = va_arg(ap,char *);
printf("string %s\n",s);
break;
case 'd':
d = va_arg(ap,int);
printf("%d\n",d);
break;
}
}
va_end(ap);
}
jsmnmarker_t
nextKeyForObject(jsmnmarker_t objMarker, jsmnmarker_t keyMarker) {
}
jsmnmarker_t
valueForKey(jsmnmarker_t keyMarker) {
keyMarker.index++;
return keyMarker;
}
char * *
keysForObject(jsmnmarker_t marker) {
if (marker.index == -1) return NULL;
if (TOKEN_TYPE(marker) != JSMN_OBJECT) return NULL;
int childSize = TOKEN_SIZE(marker);
char * * keys = malloc((childSize + 1) * sizeof(char *));
jsmnmarker_t child = marker;
child.index++;
int cnt = 0;
while (cnt < childSize) {
if (TOKEN_PARENT(child) == marker.index) {
keys[cnt] = tokenText(child);
cnt++;
}
child.index++;
}
keys[cnt] = NULL;
return keys;
}
char *
tokenText(jsmnmarker_t marker) {
if (marker.index < 0) return NULL;
return strndup(TOKEN_ADDR(marker),TOKEN_LENGTH(marker));
}
void
printToken(FILE * fh, jsmnmarker_t marker) {
if (marker.index >= 0 ) {
fprintf(fh,"%.*s",TOKEN_LENGTH(marker),TOKEN_ADDR(marker));
}
else {
fprintf(fh,"unresolved reference");
}
}
void
dprintToken(int fd, jsmnmarker_t marker) {
if (marker.index >= 0 ) {
dprintf(fd,"%.*s",TOKEN_LENGTH(marker),TOKEN_ADDR(marker));
}
else {
dprintf(fd,"unresolved reference");
}
}
I know I have to return a jsmn marker, but I'm not quite sure how to create it with just the first or last name. Here is an example code that uses this function.
char * firstName = tokenText(derefBy(faculty,"ds",i,"firstName"));
char * lastName = tokenText(derefBy(faculty,"ds",i,"lastName"));
fprintf(stdout,"Prof. %s %s \n",firstName,lastName);
My confusion is based on the results. It seems completely random that I either get
Faculty Schedules
0
string firstName
0
string lastName
Prof. (null) (null)
0
string classes
Segmentation fault (core dumped)
Or I get this without changing anything
Faculty Schedules
0
string firstName
Segmentation fault (core dumped)
I want it to simply produce
Prof. <firstName> <lastName>
Classes: ...
fmt is a string of 's' and 'd' characters which describes whether the remaining arguments are object keys or array indices. For example, derefBy(marker,"sds",key1, sub1, key2) would dereference marker first by key1 then index sub1 and finally key2
Related
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct stack {
int size;
int top;
char *arr;
};
int isEmpty(struct stack *ptr) {
if (ptr->top == -1)
{
return 1;
}
else
{
return 0;
}
}
int isFull(struct stack *ptr) {
if (ptr->top == ptr->size - 1)
{
return 1;
}
else
{
return 0;
}
}
int push(struct stack *ptr, int val) {
if (isFull(ptr))
{
return -1;
}
else
{
ptr->top++;
ptr->arr[ptr->top] = val;
}
return 1;
}
int pop(struct stack *ptr) {
if (isEmpty(ptr))
{
return -1;
}
else
{
ptr->top--;
int val = ptr->arr[ptr->top];
return val;
}
}
int stackTop(struct stack *ptr) {
return ptr->arr[ptr->top];
}
int precedence(char ch) {
if (ch == '/' || ch == '*')
{
return 3;
}
else if (ch == '+' || ch == '-')
{
return 2;
}
else
{
return 0;
}
}
int isOperand(char ch) {
if (ch == '+' || ch == '-' || ch == '/' || ch == '*')
{
return 1;
}
else
{
return 0;
}
}
char IntoPostFix(char *Infix) {
struct stack *s = (struct stack *)malloc(sizeof(struct stack));
s->top = -1;
s->size = 100;
s->arr = (char *)malloc(s->size * sizeof(char));
char *postfix = (char *)malloc(strlen(Infix + 1) * sizeof(char));
int i = 0; //value at intfix;
int j = 0; //store into post fix
while (Infix[i] != '\0')
{
if (!isOperand(Infix[i]))
{
postfix[j] = Infix[i];
i++;
j++;
}
else
{
if (precedence(Infix[i]) > precedence(stackTop(s)))
{
push(s, Infix[i]);
i++;
}
else
{
postfix[j] = pop(s);
j++;
}
}
}
while (!isEmpty(s))
{
postfix[j] = pop(s);
j++;
}
postfix[j] = '\0';
return postfix[j];
}
int main() {
char *Infix = "a-b";
printf("PostFix is : %s\n ", IntoPostFix(Infix));
return 0;
}
You format string expects a string but you give it a char:
printf("PostFix is : %s\n ", IntoPostFix(Infix));
Change the signature and return postfix instead of the '\0':
char *IntoPostFix(char *Infix) {
...
return postfix;
}
It now prints "ab\n ", that is, we correctly process 'a', 'b', and '-' is pushed on the stack. pop(s) return 0 you decrement top before you return the value:
ptr->top--;
int val = ptr->arr[ptr->top];
return val;
instead do:
return ptr->arr[ptr->top--];
and voila:
PostFix is : ab-
Bonus round:
In IntoPostFix you call malloc() 3 times and don't call free() so your program leaks memory.
Instead of strlen(Infix + 1) which evaluates to strlen(Infix) - 1 you want strlen(Infix) + 1.
Instead of while (Infix[i] != '\0') consider using a for() loop to reduce the scope of the variable i. Avoid negation and use continue for less branching noise. If you use this style of compressing newlines you get about twice as much code on the screen at a time:
for(int i = 0; Infix[i]; ) {
if(isOperand(Infix[i])) {
if(precedence(Infix[i]) > precedence(stackTop(s))) {
push(s, Infix[i++]);
} else {
postfix[j++] = pop(s);
}
continue;
}
postfix[j++] = Infix[i++];
}
I am new to C and am trying to code up a data structure, primarily, a ternary search tree. I am working under the assumption (for now) that valid char inputs are being passed in. I am having some issues with my insert function. Note that I am also inserting the original string in the last TSTnode where the last character of str will also be held.
Here is what I have so far
struct TSTnode {
char* word; // NULL if no word ends here
char self;
struct TSTnode *left, *sub, *right;
};
int insert_tst(struct TSTnode** tree, const char* str) {
return _insert(tree, str, 0);
}
int _insert(struct TSTnode** tree, const char* str, int position) {
if((*tree) == NULL) {
*tree = new_tst_node(*(str+position));
position = position + 1;
if(*(str+position) == '\0') {
(*tree)->word = strcpy((*tree)->word,str);
return 1;
}
}
else if ((*tree)->self > *(str+position)) {
position = position + 1;
_insert( &((*tree)->left), str, position);
}
else if ((*tree)->self < *(str+position)) {
position = position + 1;
_insert( &((*tree)->right), str, position);
}
else {
position = position + 1;
_insert( &((*tree)->sub), str, position);
}
return 0;
}
struct TSTnode* new_tst_node(char self) {
struct TSTnode* newNode = (struct TSTnode*) malloc(sizeof(struct
TSTnode));
if (newNode == NULL) {
return NULL;
}
newNode->word = NULL;
newNode->self = self;
newNode->left = NULL;
newNode->right = NULL;
newNode->sub = NULL;
return newNode;
}
Here is how I am testing:
struct TSTnode* tree = NULL;
char* words[1] = {"hello"};
for (int i = 0; i < 1; i++) {
if (insert_tst(&tree, words[i]) == 0) {
//print some error
}
else { //success }
EDIT - My issue is that none of my conditional branches are being taken and the insert function simply goes straight to return 0.
Note: You confusingly use tree for both TSTnode* and TSTnode**. I'm going to use tree_ptr for the latter, and pretend that you did the same.
Your claim is false. The body of if((*tree_ptr) == NULL) is executed. You do have a number of problems, though.
You don't handle the case where *tree_ptr == NULL && *(str+position+1) != '\0'.
You don't correctly handle the case where *tree_ptr != NULL && *(str+position+1) == '\0'.
You always return 0 when *tree_ptr != NULL || str[1] != '\0'.
You never allocate word, but you deference it. The thing is, you shouldn't be storing the string again anyway!
You don't handle the case where str[0] == '\0' (empty string).
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
return insert_tst_helper(tree_ptr, str, 0);
}
int insert_tst_helper(struct TSTnode** tree_ptr, const char* str, int position) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*(str+position));
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (*(str+position+1) == '\0') { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
else if ((*tree_ptr)->self > *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->left), str, position);
}
else if ((*tree_ptr)->self < *(str+position)) {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->right), str, position);
}
else {
position = position + 1;
return insert_tst_helper( &((*tree_ptr)->sub), str, position);
}
}
Untested.
Let's clean this up, though.
*(str+position)simplifies tostr[position]
ch == '\0'simplifies toch == 0then to!ch
position = position + 1; return insert_tst_helper(..., str, position);simplifies to++position; return insert_tst_helper(..., str, position);then toreturn insert_tst_helper(..., str, position+1);then toreturn insert_tst_helper(..., str+1, 0);then toreturn insert_tst(..., str+1);
Why is recursion being used at all???
Fixed:
int insert_tst(struct TSTnode** tree_ptr, const char* str) {
if (!*str)
return 0; /* Zero-length strings are not supported. */
while (1) {
if (*tree_ptr == NULL) {
*tree_ptr = new_tst_node(*str);
if (*tree_ptr == NULL)
return 0; /* Memory allocation error. */
}
if (!*(str+1)) { /* If the next char is a NUL */
(*tree_ptr)->is_word = 1;
return 1;
}
int cmp = *str - (*tree_ptr)->self;
if (cmp < 0) { tree_ptr = &( (*tree_ptr)->left ); }
else if (cmp > 0) { tree_ptr = &( (*tree_ptr)->right ); }
else { tree_ptr = &( (*tree_ptr)->sub ); }
++str;
}
}
Untested.
I am reading from a txt file into an array of structures. Example txt:
-4.5 -1 0 0
4.0 1 0 0
8 0 1 2
12.1 0 -6 1
-3.2 2.5 -3.0 4
The 4 values of each line correspond to the 4 values in the structure. The file may contain up to 100 lines (MAX is defined as 100). With the following code I am trying to store each line into the respective index of the struct array and then print:
FILE *fileName = NULL;
typedef struct chargeData_struct {
double Q, x, y, z;
} ChargeData;
ChargeData values[MAX], *p = values;
fileName = fopen("charge2.txt", "r");
if (fileName == NULL)
{
printf("ERROR: Could not open file.");
}
int k = 0;
while (fscanf(fileName, "%lf %lf %lf %lf", &p[k].Q, &p[k].x, &p[k].y, &p[k].z) != EOF);
{
printf("%f %f %f %f\n", p[k].Q, p[k].x, p[k].y, p[k].z);
k++;
}
fclose(fileName);
However, only the last line of the txt file is printed. Is the same index of the struct array being overwritten each time?
You are using an extra semicolon which makes all the trouble, here:
while (fscanf(...) != EOF);
{
...
Remove it and you should be fine.
What happens with your code is that while(..); is equivalent to this:
while(...)
{
; // do nothing
}
thus does not enter the body (the one you think is the body) of your loop (since the actual body does nothing). However scanf() continues to parse the file, and then this section of your code executes:
{
printf("%f %f %f %f\n", p[k].Q, p[k].x, p[k].y, p[k].z);
k++;
}
independently, where the curly braces are treated like they wanted to state scope.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define LINE_BUFFER_LEN (512)
#define RESERVE_NEWLINDE 0
#define AUTO_FILTER_NEWLINDE 1
typedef int (* LINE_READER)(char * pstrLine, int uiBufferLen, void * pvData);
typedef struct st_HW_SSP_CONFIG
{
const char * pstrConfigPath;
LINE_READER pfLineReader;
FILE * pstFile;
void * pvData;
int CurrentLine;
int Flag;
} CONFIG_ST;
int CloseConfig(CONFIG_ST * pstConfig)
{
if (!pstConfig)
{
// record error
return -1;
}
if (fclose(pstConfig->pstFile))
{
// record error
}
return 0;
}
int OpenConfigFile(const char * pstrFilePath, CONFIG_ST * pstConfig)
{
FILE * pstFile = NULL;
if ((!pstrFilePath) || (!pstConfig))
{
return -1;
}
pstFile = fopen(pstrFilePath, "r");
if (!pstFile)
{
return -1;
}
pstConfig->pstFile = pstFile;
pstConfig->pstrConfigPath = pstrFilePath;
pstConfig->Flag = RESERVE_NEWLINDE;
return 0;
}
int IsNullStr(const char *pcStr)
{
const char *pcTmp = pcStr;
while ('\0' != *pcTmp)
{
if (!isspace(*pcTmp))
{
return 0;
}
pcTmp++;
}
return 1;
}
int IsEffectiveLine(char acFileLineBuffer[LINE_BUFFER_LEN])
{
if (0 == strlen(&acFileLineBuffer[0]))
{
return 0;
}
if ('#' == acFileLineBuffer[0]) // strip as a comment line
{
return 0;
}
if (IsNullStr(&acFileLineBuffer[0]))
{
return 0;
}
return 1;
}
void FilterNewLine(char* pcLine, int MaxNumLen)
{
int uiLen = strlen(pcLine);
if (uiLen > 1)
{
if ('\n' == pcLine[uiLen - 1])
{
pcLine[uiLen - 1] = '\0';
if (uiLen > 2)
{
if ('\r' == pcLine[uiLen - 2])
{
pcLine[uiLen - 2] = '\0';
}
}
}
}
return;
}
int ReadConfigFile(CONFIG_ST * pstConfig)
{
char acFileLineBuffer[LINE_BUFFER_LEN] = {0};
char * pstrRead = NULL;
int Ret = 0;
if (!pstConfig)
{
return -1;
}
if ((!pstConfig->pstFile) || (!pstConfig->pfLineReader))
{
return -1;
}
rewind(pstConfig->pstFile);
pstConfig->CurrentLine = 0;
do
{
memset((void *)&acFileLineBuffer[0], 0, LINE_BUFFER_LEN);
pstrRead = fgets(&acFileLineBuffer[0], LINE_BUFFER_LEN - 1, pstConfig->pstFile);
if (pstrRead)
{
pstConfig->CurrentLine ++;
if (0 == IsEffectiveLine(acFileLineBuffer))
{
continue;
}
if (AUTO_FILTER_NEWLINDE == pstConfig->Flag)
{
FilterNewLine(acFileLineBuffer, LINE_BUFFER_LEN - 1);
}
if (pstConfig->pfLineReader)
{
Ret = pstConfig->pfLineReader(&acFileLineBuffer[0],
LINE_BUFFER_LEN,
pstConfig->pvData);
if (Ret)
{
break;
}
}
}
}
while (pstrRead);
return Ret;
}
int ReadConfigFileEx(const char * pFilePath,
LINE_READER pfReader,
void * pData, int Flag)
{
int Ret = 0;
CONFIG_ST stConfig = {0};
Ret = OpenConfigFile(pFilePath, &stConfig);
if (Ret)
{
return Ret;
}
stConfig.pfLineReader = pfReader;
stConfig.pvData = pData;
stConfig.Flag = Flag;
Ret = ReadConfigFile(&stConfig);
CloseConfig(&stConfig);
return Ret;
}
int StringSplit(char *pcStr, char cFlag,
char * pstArray[], int MaxNum,
int *pNum)
{
char * pcStrTemp = 0;
unsigned int uiIndex = 0;
pcStrTemp = pcStr;
while (pcStrTemp)
{
pstArray[uiIndex] = pcStrTemp;
pcStrTemp = strchr(pcStrTemp, cFlag);
if (pcStrTemp)
{
*pcStrTemp = '\0';
pcStrTemp ++;
uiIndex ++;
}
if (uiIndex >= MaxNum)
{
break;
}
}
if (0 != MaxNum)
{
*pNum = uiIndex >= MaxNum ? (MaxNum - 1) : uiIndex;
}
else
{
*pNum = 0;
}
return 0;
}
int MyLineReader(char * pstrLine, int uiBufferLen, void * pvData)
{
printf("Read line:[%s]\r\n", pstrLine);
char *pArray[8] = {0};
int Num = 0;
int index = 0;
StringSplit(pstrLine, ' ', pArray, 8, &Num);
for (index = 0; index <= Num; index ++)
{
printf("Get value :[%s]\r\n", pArray[index]);
}
return 0;
}
int main(int argc, char * argv[])
{
int ret = 0;
if (argc != 2)
{
printf("Please input file to read.\r\n");
return 0;
}
ret = ReadConfigFileEx(argv[1], MyLineReader, NULL, AUTO_FILTER_NEWLINDE);
if (ret)
{
printf("Open file error.\r\n");
}
return 0;
}
I am trying to fix my last problem and still, I cannot figure out how to solve it. My task was to write a program which sort numbers, but: our tutor gives us some extra points for program dealing with numbers like: 000054667 (in fact 54667) and 345_845 (in fact 345845). The first problem is already solved but I have no idea how to handle with the second one. Hence, my question is: do you have any tips/clue, which might help me? I am also sending my code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define NUMBER_CHUNK 13
char* getNumber(FILE* fp)
{
int length, c;
int current=0;
char *number;
number=(char*)malloc(sizeof(char)*NUMBER_CHUNK);
if(!number)
{
printf("Error while alocating memory!\n");
return NULL;
}
length=NUMBER_CHUNK;
while(!isspace(c=fgetc(fp)) && !feof(fp))
{
if(isdigit(c))
{
number[current]=c;
current++;
if(current>=length)
{
length+=NUMBER_CHUNK;
if((number=((char*)realloc(number,sizeof(char*)*length)))==NULL)
{
free(number);
return NULL;
}
}
}
else
{
return NULL;
}
}
number[current]='\0';
return number;
}
int compare( const void *str1, const void *str2)
{
int value;
char* curr1;
char* curr2;
curr1=*(char**)str1;
curr2=*(char**)str2;
while(*curr1=='0') curr1++;
while(*curr2=='0') curr2++;
if(strlen(curr1) < strlen(curr2)) return -1;
if(strlen(curr1) > strlen(curr2)) return 1;
value=strcmp(curr1, curr2);
return value;
}
int main(int argc, char** argv)
{
FILE* fp;
char** tab;
int i=0;
int lines=0;
int length=10;
if(argc!=2)
{
printf("Incorrent syntax! Use ./name_of_program input_file\n");
return 1;
}
if(!(fp=fopen(argv[1],"r")))
{
printf("Could not open the file! Please try again!\n");
return 2;
}
tab = (char**)malloc(length*(sizeof(char*)));
if(!tab)
{
printf("Could not allocate memory! Terminating...\n");
free(tab);
return 3;
}
while(!feof(fp))
{
tab[i]=getNumber(fp);
if(i>=length)
{
length+=10;
if((tab=((char**)realloc(tab,sizeof(char*)*length)))==NULL)
{
free(tab);
return 5;
}
}
if(tab[i]==NULL)
{
printf("Incorrect character in the infile! Terminating\n");
free(tab);
return 4;
}
if(*tab[i]=='\0')
{
free(tab[i]);
i--;
}
i++;
lines++;
lines=i;
}
printf("\nBEFORE\n");
for(i=0;i<lines;i++)
{
printf("%s\n",tab[i]);
}
qsort(tab, lines, sizeof(char*), &compare);
printf("\nAFTER\n");
for(i=0;i<lines;i++)
{
printf("%s\n",tab[i]);
free(tab[i]);
}
free(tab);
fclose(fp);
return 0;
}
Thank you for any help ;)
Change string accumulation and your compare routine.
String accumulation:
if(isdigit(c) || (c == '_'))
Compare. This is a bit lengthy to incorporate ignoring _ for value ratings. But it is not limited to numbers that fit in any int range.
int compare(const void *str1, const void *str2) {
const char* curr1 = *(const char**) str1;
const char* curr2 = *(const char**) str2;
// Remove leading zeros
while ((*curr1 == '0') || (*curr1 == '_'))
curr1++;
while ((*curr2 == '0') || (*curr2 == '_'))
curr2++;
int value = 0;
size_t len1 = 0;
size_t len2 = 0;
while (*curr1 || *curr2) {
while (*curr1 == '_')
curr1++;
while (*curr2 == '_')
curr2++;
// If a difference has not been found yet ...
if (value == 0) {
value = *curr1 - *curr2;
}
if (*curr1) {
curr1++;
len1++;
}
if (*curr2) {
curr2++;
len2++;
}
}
// If significant digits in string1 more than string2 ...
if (len1 != len2) {
return (len1 > len2) ? 1 : -1;
}
return value;
}
Just keep parsing the string until you get an underscore, and with parsing also convert each character into the respective number and keep adding it to a new number according to it's place value (In a nutshell i'm speaking of an algorithm to convert string to numbers). and if you encounter an underscore, just use
continue;
If you want to retain the string representation for your "numbers" but compare them according to their numerical value, don't compare them as strings inside your compare function.
Inside compare parse each arguments (str1 and str2) and convert them to numbers skipping leading zeros and underscores. Once you have two numbers (say num1 and num2) just return num1 - num2.
Instead of storing a bunch of strings, you would be better off converting the numbers to ints by stripping out any non-digit characters and calling atoi on the results. You can store those numbers directly in the array. The compare function then becomes much simpler.
chux THX. You're brilliant! I wish I would be as good as you in programming.
I am sending my whole (fixed, working) source code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define NUMBER_CHUNK 13
char* getNumber(FILE* fp)
{
int length;
int current = 0;
int c;
char *number, *number2;
number = (char*)malloc(sizeof(char)*NUMBER_CHUNK);
if(!number)
{
printf("Error while allocating memory!\n");
return NULL;
}
length = NUMBER_CHUNK;
while(!isspace(c = fgetc(fp)) && !feof(fp))
{
if(isdigit(c) || c == '_')
{
number[current] = c;
current++;
if(current >= length)
{
length+=NUMBER_CHUNK;
number2 = (char*)realloc(number,length*sizeof(char*));
if(number2 == NULL)
{
free(number2);
return NULL;
}
else number2 = number;
}
}
else
{
return NULL;
}
}
number[current] = '\0';
return number;
}
int compare(const void *str1, const void *str2)
{
char* curr1;
char* curr2;
curr1=*(char**)str1;
curr2=*(char**)str2;
while(*curr1=='0' || *curr1=='_') curr1++;
while(*curr2=='0' || *curr2=='_') curr2++;
int value = 0;
size_t len1 = 0;
size_t len2 = 0;
while(*curr1 || *curr2)
{
while(*curr1 == '_')
curr1++;
while(*curr2 == '_')
curr2++;
if(value == 0)
{
value = *curr1 - *curr2;
}
if(*curr1)
{
curr1++;
len1++;
}
if(*curr2)
{
curr2++;
len2++;
}
}
if(len1 != len2)
{
return (len1 > len2) ? 1 : -1;
}
return value;
}
int main(int argc, char** argv)
{
FILE* fp;
char** tab;
int i = 0;
int lines = 0;
int length = 10;
if(argc != 2)
{
printf("Incorrent syntax! Use ./name_of_program input_file\n");
return 1;
}
if(!(fp = fopen(argv[1],"r")))
{
printf("Could not open the file! Please try again!\n");
return 2;
}
tab = (char**)malloc(length*(sizeof(char*)));
if(!tab)
{
printf("Could not allocate memory!\n");
free(tab);
return 3;
}
while(!feof(fp))
{
tab[i] = getNumber(fp);
if(i >= length)
{
length += 10;
tab = (char**)realloc(tab,sizeof(char*));
if(tab == NULL)
{
free(tab);
return 5;
}
}
if(tab[i] == NULL)
{
printf("Incorrect character in the infile! Terminating\n");
free(tab);
return 4;
}
if(*tab[i] == '\0')
{
free(tab[i]);
i--;
}
i++;
lines = i;
}
printf("\nBEFORE\n");
for(i = 0 ; i < lines; i++)
{
printf("%s\n", tab[i]);
}
qsort(tab, lines, sizeof(char*), compare);
printf("\nAFTER\n");
for(i = 0; i < lines; i++)
{
printf("%s\n",tab[i]);
free(tab[i]);
}
printf("\n");
free(tab);
fclose(fp);
return 0;
}
in the following code when ran will produce a Segmentation Fault, due to a FILE* being passed to fclose which contains no address (NULL).
I'm wondering why this is happening, the FILE* isn't being used what so over.
The FILE* is named urandom and is passed to fclose in the main function.
Thanks
#include <stdio.h>
#include <stdlib.h>
struct property
{
char *name;
unsigned int value;
unsigned int owner;
unsigned int type;
};
struct player
{
unsigned int id;
unsigned int money;
unsigned int position;
};
int rollDice(FILE *);
int amountOfLines(FILE *);
int createArrayOfPtrs(int ,void ***);
int makeArryOfPropertyPtrs(int ,struct property **);
int FillArryPropertyData(struct property **,int ,FILE *);
int splitBuffer(char *,unsigned int *,char **);
int bufferPropertyFile(FILE *,char **,int );
i nt fillPropertyStruct(struct property *,unsigned int ,char *);
int main(void)
{
int linesInPropertyFile = 0;
struct property **arrayForProperties = 0;
//Open /dev/urandom for rollDice
FILE *urandom = fopen("/dev/urandom","rb");
FILE *propertyFile = fopen("/home/jordan/Documents/Programming/Monopoly Project/properties","rb");
if(propertyFile == NULL || urandom == NULL)
{
puts("ERROR: error in opening file(s)");
return 1;
}
linesInPropertyFile = amountOfLines(propertyFile);
//DEBUG
printf("%d is contained within \"linesInPropertyFile\"\n",linesInPropertyFile);
if(createArrayOfPtrs(linesInPropertyFile,(void ***)&arrayForProperties))
{
puts("ERROR: error from createArrayOfPointers()");
return 1;
}
//DEBUG
printf("Outside Pointer: %p\n",arrayForProperties);
if(makeArryOfPropertyPtrs(linesInPropertyFile,arrayForProperties))
{
puts("ERROR: error from createArrayOfPointersForProperties()");
return 1;
}
if(FillArryPropertyData(arrayForProperties,linesInPropertyFile,propertyFile))
{
puts("ERROR: error from FillArryPropertyData()");
}
//Close FILE stream for /dev/urandom
fclose(urandom);
fclose(propertyFile);
return 0;
}
int FillArryPropertyData(struct property **array,int amntOfProperties,FILE *fp)
{
int bufferUsed = 100;
int i = 0;
int returnValue = 0;
int returnValue2 = 0;
unsigned int money = 0;
char *name;
char *buffer;
rewind(fp);
while(returnValue == 0)
{
buffer = malloc(bufferUsed);
returnValue = bufferPropertyFile(fp,&buffer,bufferUsed);
if(returnValue && returnValue != -1)
{
puts("ERROR: error from bufferPropertyFile()");
return -1;
}
if(returnValue == -1)
{
break;
}
if(buffer[0] != '\0')
{
returnValue2 = splitBuffer(buffer,&money,&name);
}
if(returnValue2)
{
puts("ERROR: error in splitBuffer()");
return 1;
}
if(fillPropertyStruct(array[i],money,name))
{
puts("ERROR: error in fillPropertyStruct()");
return 1;
}
money = 0;
i++;
}
free(buffer);
return 0;
}
int fillPropertyStruct(struct property *array,unsigned int money,char *name)
{
int nameSize = 100;
int i = 0;
array->name = malloc(nameSize);
array->value = money;
while(1)
{
if(i >= nameSize)
{
void *tmp = realloc(array->name,nameSize * 2);
nameSize *= 2;
if(tmp)
{
array->name = tmp;
}
else
{
return -1;
}
}
if(name[i] == '\0')
{
break;
}
array->name[i] = name[i];
i++;
}
array->name[i] = '\0';
return 0;
}
int splitBuffer(char *buffer,unsigned int *money,char **name)
{
int i = 0;
int j = 1;
int nameSize = 100;
*name = malloc(nameSize);
while(1)
{
if(buffer[j] != '"')
{
(*name)[j-1] = buffer[j];
}
else
{
i++;
}
j++;
if(i)
{
break;
}
if(j >= nameSize)
{
void *tmp = 0;
tmp = realloc(*name,nameSize * 2);
nameSize = nameSize * 2;
if(tmp != NULL)
{
*name = tmp;
}
else
{
puts("ERROR: error in splitBuffer");
return -1;
}
}
}
name[j-1] = '\0';
while(buffer[j] != '$')
{
if(buffer[j] == '\0')
{
puts("ERROR: error in splitBuffer()");
return -2;
}
j++;
}
j++;
while(buffer[j] != '\0')
{
*money += (buffer[j] - '0');
if(buffer[j+1] != '\0')
{
*money *= 10;
}
j++;
}
printf("BUFFER: %s\n",buffer);
printf("NAME: %s\n",*name);
printf("MONEY: %d\n",*money);
return 0;
}
int bufferPropertyFile(FILE *fp,char **buffer,int i)
{
int j = (i - i);
if(feof(fp))
{
//-1 Returned if EOF detected
return -1;
}
char retr = 0;
while(1)
{
if(j + 1 >= i)
{
void *tmp = realloc(*buffer,i * 2);
if(tmp != NULL)
{
*buffer = tmp;
i = i * 2;
}
else
{
puts("ERROR: error in bufferPropertyFile()");
return -2;
}
}
retr = fgetc(fp);
if(retr == '\n' || feof(fp))
{
break;
}
(*buffer)[j] = retr;
j++;
}
(*buffer)[j] = '\0';
if(**buffer == '\0')
{
return -1;
}
return 0;
}
int rollDice(FILE *fp)
{
int seed = fgetc(fp);
srand(seed);
return (rand() % 6) + 1;
}
int amountOfLines(FILE *file)
{
int i = 0;
int retr = 0;
while(1)
{
retr = fgetc(file);
if(retr == EOF)
{
break;
}
if(retr == '\n' )
{
i++;
}
}
return i;
}
int createArrayOfPtrs(int numberOfPointers,void ***pointer)
{
void *tmp = malloc(numberOfPointers * sizeof (tmp));
if(tmp != NULL)
{
*pointer = tmp;
//DEBUG
printf("Pointer: %p\n",*pointer);
}
else
{
return 1;
}
return 0;
}
int makeArryOfPropertyPtrs(int numberOfPointers,struct property **pointer)
{
int i = 0;
void *tmp;
for(i = 0;i < numberOfPointers;i++)
{
tmp = malloc(sizeof(struct property));
if(tmp == NULL)
{
return 1;
}
pointer[i] = (struct property *)tmp;
}
return 0;
}
here it givest an access violation in splitBuffer on this line:
name[j-1]='\0';
which probably should be
(*name)[j-1]='\0';
indeed that memory is not allocated anywhere, in other words, undefined behaviour, which indeed in your case might overwrite the urandom variable: both urandom and name are allocated on stack so depending on value of j it might write over urandom..
apart from that, there might be more errors, the number and use of pointers/mallocs/reallocs and lack of frees is a bit scary
int createArrayOfPtrs(int ,void ***);
if(createArrayOfPtrs(linesInPropertyFile,(void ***)&arrayForProperties))
This is undefined behaviour, a (void***) is not compatible to a (struct property ***). Why do you even use it here, all the other functions use struct property pointers?
Since the array is located right before the file pointer in the local variables of main, maybe the problem is that the array creation/initialization overwrites urandom?