-
Passing struct pointers
OK, so this program is made to read text files, split the lines into types (based on content of the lines), and then, (eventually), create a binary file from selected descriptions and their child code lines. My problem is, in trying to compartmentalize (I can't think of the proper programming term) my code and make more functions, I pass the pointer to a struct I made and proceed to read and modify members of that struct. My question is, in passing the pointer to the struct, if the functionality of the program remains the same, and the end result is the same, why would I get the warning:
"C:\sources\test\main.c||In function 'main':|
C:\sources\test\main.c|199|warning: passing argument 1 of 'writeFile' from incompatible pointer type|
C:\sources\test\main.c|61|note: expected 'struct txtData *' but argument is of type 'struct txtData (*)[(unsigned int)(line + 1)]'|"
The .c file is here:
Code:
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "main.h"
void spaceOut(char ........tr, char *dStr)
{
strncpy(dStr, sStr, 8);
dStr[8] = '\0';
char *p = strchr(sStr,' ') + 1;
strncat(dStr, p, 8);
dStr[16] = '\0';
}
void str2Bin(char *hstr, char *dstr)
{
int num = 0;
char sstr[2];
hToIkey key[16] = {
{'0',0},
{'1',1},
{'2',2},
{'3',3},
{'4',4},
{'5',5},
{'6',6},
{'7',7},
{'8',8},
{'9',9},
{'A',10},
{'B',11},
{'C',12},
{'D',13},
{'E',14},
{'F',15}
};
int dindex = 0;
for (int i = 0; i < 16; i++)
{
for (int k = 0; k < 16; k++)
{
if (hstr[i] == key[k].keyHex)
{
num += key[k].keyDec*pow(16,(i%2)^1);
if (i%2 == 1)
{
dstr[dindex] = num;
dindex++;
num = 0;
break;
}
}
}
}
dstr[dindex] = '\0';
}
void writeFile(txtData *data, int lines)
{
char fileStart[8] = {
0,
208,
192,
222,
0,
208,
192,
222
};
char fileEnd[8] = {
240,
0,
0,
0,
0,
0,
0,
0
};
char filename[11];
int printed = 0;
for(int i = 0; i < 6; i++)
{
data[0].lineText[i] = toupper(data[0].lineText[i]);
}
sprintf(filename, "%s.gct", data[0].lineText);
data[5].lineActive = 1;
FILE *gct = fopen(filename, "w");
fwrite(&fileStart, 1, 8, gct);
for(int i = 0; i < lines; i++)
{
if (data[i].lineType == LINE_CODE)
{
if(data[data[i].parentLine].lineActive)
{
str2Bin(data[i].lineText, data[i].codeValue);
fwrite(data[i].codeValue, 1, 8, gct);
printed++;
}
}
}
fwrite(&fileEnd, 1, 8, gct);
fclose(gct);
if(printed == 0)
{
remove(filename);
printf("Create failed. No codes selected!");
}
fclose(gct);
}
int main()
{
FILE *textFile = fopen("Metroid Prime Trilogy.txt", "r");
char text[256];
char nospace[9];
char match[17] = "0123456789ABCDEF ";
char xmatch[18] = "0123456789ABCDEFX ";
int line = 0;
int parent = 0;
while(fgets(text, 255, textFile))
{
if(feof(textFile))
break;
line++;
}
txtData data[line+1];
rewind(textFile);
line = 0;
while(fgets(text, 255, textFile))
{
strncpy(data[line].lineText, text, strlen(text) - 1);
data[line].lineText[strlen(text) - 1] = '\0';
data[line].lineNum = line;
data[line].lineActive = 0;
data[line].parentLine = 0;
if(feof(textFile))
break;
line++;
}
for(int i = 0; i < line; i++)
{
int span = strspn(data[i].lineText, match);
int xspan = strspn(data[i].lineText, xmatch);
if(i == 0)
{
data[i].lineType = LINE_ID;
}
else if(strlen(data[i].lineText) == 0)
{
data[i].lineType = LINE_BLANK;
}
else if(data[i-1].lineType == LINE_ID)
{
data[i].lineType = LINE_TITLE;
}
else if((span == 17) || (xspan == 17))
{
data[i].lineType = LINE_CODE;
data[i].parentLine = parent;
spaceOut(data[i].lineText, nospace);
strcpy(data[i].lineText, nospace);
}
else if(data[i-1].lineType == LINE_BLANK)
{
if(strlen(data[i+1].lineText) == 0)
{
data[i].lineType = LINE_CATEGORY;
}
else
{
data[i].lineType = LINE_DESCR;
parent = data[i].lineNum;
}
}
else if(data[i-1].lineType == LINE_CODE)
{
data[i].lineType = LINE_COMMENT;
data[i].parentLine = parent;
}
else
{
data[i].lineType = LINE_UNKNOWN;
}
}
typeStruct types[8] = {
"ID\0",
"TITLE\0",
"CATEGORY\0",
"DESCR\0",
"CODE\0",
"COMMENT\0",
"BLANK\0",
"UNKNOWN\0"
};
writeFile(&data, line);
return 0;
}
And the header:
Code:
enum {
LINE_ID,
LINE_TITLE,
LINE_CATEGORY,
LINE_DESCR,
LINE_CODE,
LINE_COMMENT,
LINE_BLANK,
LINE_UNKNOWN
};
typedef struct {
const char keyHex;
int keyDec;
} hToIkey;
typedef struct {
int lineType;
int lineNum;
int parentLine;
char lineText[255];
char codeValue[9];
int lineActive;
} txtData;
typedef struct {
char typeValue[9];
} typeStruct;
I don't need any help on functionality, I just am puzzled by the warning and want to make sure it's resolved (if it needs to be) before moving forward.
Edit: went back and, for sake of ease, highlighted the two lines mentioned in the warning.
-
> writeFile(&data, line);
Data is already an array, so it would be
writeFile(data, line);
However, there are more issues.
> txtData data[line+1];
line is zero to begin with, so this is an array with only 1 slot.
Then you go on to calculate a new value of line, but this does NOT alter your array.
> strncpy(data[line].lineText, text, strlen(text) - 1);
> data[line].lineText[strlen(text) - 1] = '\0';
strncpy() only offers safety if you use the size of the destination, not the size of the source.
You have written precisely
strcpy( data[line].lineText, text );
> if(feof(textFile))
> break;
a) it's too late to test this now inside the loop, you've already processed the data
b) it's unreachable to begin with - the use of fgets() in the while loop sees to that.
Just delete these two lines.
-
Code:
txtData data[line+1];
...
writeFile(&data, line);
When you use the name "data", it becomes type txtData* (pointer to txtData). &data then would be txtDat........... You should read the FAQ about pointers and arrays.
-
Thank you for the hint about data already being an array, as that's all I needed, and the clarification on strncpy was useful, but line is perfectly fine the way it is. Thanks anyway.
-
> for(int i = 0; i < line; i++)
...
> data[i].lineType = LINE_ID;
I wonder how far this overwriting past the end of the array will go before "it's fine" turns into "What's a segfault?"
-
Umm, it's not overwriting past the array. Look closer at the code:
Code:
int line = 0;
int parent = 0;
while(fgets(text, 255, textFile))
{
if(feof(textFile))
break;
line++;
}
txtData data[line+1];
rewind(textFile);
line = 0;
while(fgets(text, 255, textFile))
{
strcpy(data[line].lineText, text);
data[line].lineText[strlen(text) - 1] = '\0';
data[line].lineNum = line;
data[line].lineActive = 0;
data[line].parentLine = 0;
if(feof(textFile))
break;
line++;
}
As you can see, there are two loops with fgets. The first one determines how many lines there are in the file (line++) which then is used to create the struct array with proper number of elements before being reset to zero.
Also, as it turns out, it's not too late, for my purposes, to check feof inside the loop, as without it, I actually get an added garbage slot in my array. True, I could leave it out and do "txtData data[line]" instead of "data[line+1]", but your premise was off.