2d Array - Each Row being Overwritten by Next - c

I'm reading in from a file. Whenever I read in the word 'transition' I'm trying to add the next 5 elements that appear to a 2d array. I have a bunch of printf's which I have commented out that show that I am adding the proper element. However, once I finish reading in from file, I loop through to check my 2d array values and they have all been overwritten by the last row's values.
Here is my code
State* allStates[1002];
State* currentState;
char* input = argv[1];
char* inputStr = argv[2];
int maxTrans = atoi(argv[3]);
int transCount = -1;
FILE* inputFile;
char* transition[maxTrans][5];
inputFile = fopen(input, "r");
if (inputFile == 0)
{
perror("Can't open file\n");
exit(-1);
}
else
{
char next[1000];
//int counter = 0;
while (fgets(next, 1000, inputFile) != NULL)
{
char *nextWord;
nextWord = strtok_r(next, "\t");
if (strcmp(nextWord, "state") == 0)
{
//counter++;
nextWord = strtok_r(NULL, "\t");
//puts(nextWord);
int q = atoi(nextWord);
nextWord = strtok_r(NULL, "\n");
//puts(nextWord);
if (strcmp(nextWord, "accept") == 0)
{
State* newState = makeState(q, 1, 0, 0);
allStates[q] = newState;
}
else if (strcmp(nextWord, "reject") == 0)
{
State* newState = makeState(q, 0, 1, 0);
allStates[q] = newState;
}
else if (strcmp(nextWord, "start") == 0)
{
State* newState = makeState(q, 0, 0, 1);
allStates[q] = newState;
currentState = newState;
}
else
{
State* newState = makeState(q, 0, 0, 0);
allStates[q] = newState;
}
}
if (strcmp(nextWord, "transition") == 0)
{
//printf("\n");
//setup 2d array of transitions
transCount++;
nextWord = strtok_r(NULL, "\t");
//puts(nextWord);
transition[transCount][0] = nextWord;
//printf("%c", *transition[transCount][0]);
nextWord = strtok_r(NULL, "\t");
//puts(nextWord);
transition[transCount][1] = nextWord;
//printf("%c", *transition[transCount][1]);
nextWord = strtok_r(NULL, "\t");
//puts(nextWord);
transition[transCount][2] = nextWord;
//printf("%c", *transition[transCount][2]);
nextWord = strtok_r(NULL, "\t");
//puts(nextWord);
transition[transCount][3] = nextWord;
//printf("%c", *transition[transCount][3]);
nextWord = strtok_r(NULL, "\n");
//puts(nextWord);
transition[transCount][4] = nextWord;
//printf("%c", *transition[transCount][4]);
}
}
}
fclose(inputFile);
int u = 0;
int y = 0;
char m = 'm';
for (u; u < 12; u++)
{
printf("\n");
for (y = 0; y < 5; y++)
{
//transition[u][y] = &m;
printf("%c", *transition[u][y]);
}
}
If the file I'm reading in looks like this,
transition 0 x 0 x R
transition 0 1 4 1 L
transition 0 0 1 x R
I expect the array to look like this
0x0xR
0141L
001xR
Instead the values of the array will be
001xR
001xR
001xR
I know that the overwriting happens at each row. ie: when I'm writing to row 2 the values become:
0141L
0141L
I'm really lost as to how to fix it though.

The problem was with my incorrect usage of strtok(). I took Dmitri's advice and used strdup() which allocates memory for the new string and I'm getting the proper results.
nextWord = strtok(NULL, "\t");
temp = strdup(nextWord);
transition[transCount][0] = temp;

Related

I am trying to write SQL part for CSV in C. Why will the code below distort result without duplicating TCHAR * arguments?

The code I write is in C on Visual studio 2022.. I don't understand what part of my code is wrong, but it should be about string manipulation. The SplitStr splits string by another string (strtok does it by character).
#define SplitCount 20
TCHAR** SplitStr(TCHAR* pstr, TCHAR *psplitby)
{
if (pstr == NULL || psplitby == NULL)
return NULL;
TCHAR** res = malloc(SplitCount * sizeof(TCHAR*));
int i = 0, j = 0, c = 0;
TCHAR* splitby = _tcsdup(psplitby); // I need to duplicate here
int len = _tcslen(splitby);
TCHAR* str = _tcsdup(pstr); // and here
int strlen1 = _tcslen(str);
while (i < MAXSTR - strlen1) {
if (i + len < strlen1 && _tcsncmp(splitby, &str[i], len) == 0)
{
res[c] = malloc(MAXSTR * sizeof(TCHAR*));
if (res[c] == NULL)
break;
_tcsncpy_s(res[c], MAXSTR, &str[j], i-j);
i += len;
j = i;
c++;
i--;
}
i++;
}
res[c] = malloc(MAXSTR * sizeof(TCHAR*));
if (res[c] != NULL)
{
_tcsncpy_s(res[c], MAXSTR, &str[j], strlen1 - j);
c++;
}
res[c] = _tcsdup(_T("END"));
return res;
}
TCHAR* StrToLower(TCHAR* Str)
{
int i = 0;
TCHAR * tstr = malloc(MAXSTR * sizeof(TCHAR));
ZeroMemory(tstr, MAXSTR * sizeof(TCHAR));
if (tstr != NULL)
{
_tcsset_s(tstr, MAXSTR, _T('\0'));
for (; i < MAXSTR; i++)
{
tstr[i] = _totlower(Str[i]);
}
}
return tstr;
}
int SelectFromTable(TCHAR* Table, FIELDS fields[], TCHAR* Where);
int execute_sentence(TCHAR* psentence)
{
TCHAR * sentence = StrToLower(psentence);
StrTrim(sentence, _T(" "));
TCHAR* dlimiter = _T("?");
if (_tcsncmp(_T("select"), sentence, _tcslen(_T("select"))) == 0)
{
TCHAR ** split = SplitStr(sentence, _T("where"));
TCHAR* select = split[0];
StrTrim(select, _T(" "));
TCHAR* where = split[1];
StrTrim(where, _T(" "));
//_putts(where); // here value is OK
TCHAR ** split2 = SplitStr(select, _T("from"));
TCHAR * fields = split2[0] + _tcslen(_T("select"));
TCHAR * table = split2[1];
StrTrim(table, _T(" "));
_putts(where); // here value is distorted now if I don't use _tcsdup above
TCHAR ** split3 = SplitStr(fields, dlimiter);
TCHAR* thefield = split3[0];
StrTrim(thefield, _T(" "));
FIELDS fields_arr[Field_Count];
int c_field_pos = 0, i = 1;
while (_tcscmp(thefield, _T("END")) != 0)
{
StrTrim(thefield, _T(" "));
c_field_pos = 0;
if (thefield != NULL)
{
for (int i = 0; i < Field_Count; i++)
{
if (_tcsncmp(thefield, table_columns[i], _tcslen(table_columns[i])) == 0) {
fields_arr[c_field_pos] = (FIELDS)i;
c_field_pos++;
break;
}
}
}
thefield = split3[i];
i++;
}
fields_arr[c_field_pos] = F_END;
SelectFromTable(table, fields_arr, where);
}
return 0;
}
I never expected the need to duplicate, I even used a pointer and kept it intact, still problem exists..

Why am I getting this message in hackerrank "~ no response on stdout ~"? I don't know what I am missing>

Why am I getting this message in hackerrank "~ no response on stdout ~"? I don't know what I am missing?
I am bit frustrated right now because I have no clue about what to do.
So I was left with only choice to post this query on Stackoverflow.
Here is the link to the problem
Here is my complete code:
char* readline();
// Complete the countingValleys function below.
int countingValleys(int n, char* s)
{
int dwnhl = 0, level = 0;
bool frmsurface = true;
int k = strlen(s);
for (int i = 0; i < k; i++)
{
if (level == 0)
{
frmsurface = true;
}
if (s[i] == 'D')
{
level--;
if ((level < 0) && (frmsurface == true))
{
dwnhl++;
frmsurface = false;
//printf("went downhill %d ",i);
}
}
else if (s[i] == 'U')
{ //printf("went uphill %d ",i);
level++;
}
// printf("\nhello - %c",s[i]);
}
printf("\nNumber of downhill = %d \n", dwnhl);
return (dwnhl);
}
int main()
{
FILE* fptr = fopen(getenv("OUTPUT_PATH"), "w");
char* n_endptr;
char* n_str = readline();
int n = strtol(n_str, &n_endptr, 10);
if (n_endptr == n_str || *n_endptr != '\0')
{
exit(EXIT_FAILURE);
}
char* s = readline();
int result = countingValleys(n, s);
printf("%d\n", result);
return 0;
}
char* readline()
{
size_t alloc_length = 1024;
size_t data_length = 0;
char* data = malloc(alloc_length);
while (true)
{
char* cursor = data + data_length;
char* line = fgets(cursor, alloc_length - data_length, stdin);
if (!line)
{
break;
}
data_length += strlen(cursor);
if (data_length < alloc_length - 1 || data[data_length - 1] == '\n')
{
break;
}
size_t new_length = alloc_length << 1;
data = realloc(data, new_length);
if (!data)
{
break;
}
alloc_length = new_length;
}
if (data[data_length - 1] == '\n')
{
data[data_length - 1] = '\0';
}
data = realloc(data, data_length);
return data;
}
One problem is the way you handle frmsurface
The first time you enter the loop frmsurface is set to true. If the events are UUDD, your code will still count a "valley" because you don't clear frmsurface when you go up.
Instead of
if(level==0)
{
frmsurface=true;
}
you could try:
frmsurface = (level == 0);
but I don't really understand why you want the boolean. Just test for level == 0 instead. Something like:
if(s[i]=='D')
{
if(level==0)
{
dwnhl++;
}
level--;
}
else if (s[i]=='U')
{
level++;
}
Also I wonder if this line:
printf("\nNumber of downhill = %d \n", dwnhl);
must be removed.
Notice that
int k=strlen(s);
for(int i=0;i<k;i++)
could probably just be
for(int i=0;i<n;i++)
^
as n is passed to the function

mpi dynamic array memory allocation

Hello i am trying to apply a filter over a greyscale pgm image:
int contor = 0;
char *magicNumber;
char *metaData;
int imageWidth = 0, imageHeight = 0, valueRange = 0;
int *imageData;
while (EOF != fscanf(fp2, "%[^\n]\n", line))
{
if(contor == 0)
{
magicNumber = (char*)malloc((1 + strlen(line)) * sizeof(char));
strcpy(magicNumber, line);
magicNumber[strlen(magicNumber)] = '\0';
}
else if (contor == 1)
{
metaData = (char*)malloc((1 + strlen(line)) * sizeof(char));
strcpy(metaData, line);
metaData[strlen(metaData)] = '\0';
}
else if (contor == 2)
{
token = strtok(line, " ");
imageWidth = atoi(token);
token = strtok(NULL, " ");
imageHeight = atoi(token);
imageData = (int*)malloc(imageWidth * imageHeight * sizeof(int));
}
else if (contor == 3)
{
valueRange = atoi(line);
}
else
{
printf("Should put value %d in imageData at index %d\n", atoi(line), contor);
//imageData[contor-4] = atoi(line);
}
contor++;
}
My code breaks at the imageData memory allocation. width and height are correctly read and converted to int;
Can anyone tell me what i am doing wrong ?

read lines from file with fgets and compare each line with strncmp in c

i want to read every line from a file which looks something like this:
readEveryLine
{
"Bart [m]" -> "Marge [f]";
"Lisa [f]" -> "Homer [m]";
...
}
i want to use:
fgets() to read the file line by line
strncmp() to compare every line with a given string or see that it has just the right format
what i have:
while(fgets(*file_string, MAX_INPUT_STDIN, file) != NULL)
{
changeLastC(*file_string); // function to change \n into \0
if (strncmp(*file_string, "readEveryLine\0", 14) == 0)
{
if (strncmp(*file_string, "{\0", 2) == 0)
{
// check the first -> relation
}
}
else
{
printf("Error Parsing\n");
}
}
so the problem is that it just gives me an Error Parsing and i don`t know what i did wrong here.
Thanks a lot for helping me!
here i made a few things now (parsing the first two lines works now) :
maybe anyone has got a good tip for me what i could do better.
Thanks a lot.
if ((fp = fopen("df.dot","r")) == NULL)
{
printf("Error: File Open\n");
return 1;
}
int row = 0; // check row 1
while (fgets(buffer, MAX_PARSING, fp))
{
if ((row == 0) && strncmp(buffer, "readEveryLine\n", 14) == 0)
{
printf("%s", buffer);
}
else
{
printf("Parsing Error 1\n");
}
}
int row1 = 1; // check row 2
while (fgets(buffer, MAX_PARSING, fp))
{
if ((row1 == 1) && strncmp(buffer, "{\n", 2) == 0)
{
printf("%s", buffer);
}
else
{
printf("Parsing Error 2\n");
}
}
int row2 = 2; // check other rows (dynamic, could be even more or less)
while (fgets(buffer, MAX_PARSING, fp))
{
if ((row2 == 2) && strncmp(buffer, " ", 2) == 0)
{
const char *p1 = strstr(fp, "\"")+1;
const char *p2 = strstr(p1, " [m]\"");
const char *p3 = strstr(p1, " [f]\"");
// extract male persons
if (p1 && p2)
{
size_t len1 = p2 - p1;
char* res1 = (char*)malloc(sizeof(char)*(len1 + 1));
strncpy(res1, p1, len1);
res1[len1] = '\0';
// give res1 for functionMale() to work on that string
}
// extract female persons
else if (p1 && p3)
{
size_t len2 = p3 - p1;
char* res2 = (char*)malloc(sizeof(char)*(len2 + 1));
strncpy(res2, p1, len2);
res2[len2] = '\0';
// give res2 for functionFemale() to work on that string
}
else if (strcmp(buffer, " -> ") == 0)
{
// work in progress (quite complicated to do this i think)
// it has to be a realtion between two people
}
else if (strcmp(buffer, ";") == 0)
{
// work in progress
// this sign can either exist like this:
// "Bart [m]" -> "Marge [f]";
// or like this:
// "Marge [f]";
}
break;
}
else
{
printf("Parsing Error 3\n");
}
row2++;
}
// and the very last sign has to be }\n
Your algorithm is already broken.
You use the very same content of *file_string to compare it against tweo different strings.
If you find a match for "readEveryLine" you need to read the next line from your file before you can get the next match for strncmp().
Otherwise the line from the file must match both "readEveryLine" and "{" to pass your second if condition, which is impossible.
Edit:
Now as you have done some improvements I still think it will not work with your approach. The loops will not exit when they should and your if-else-cascade also does not seem to be a good idea.
In your approach you will get messed up with reading too many lines while only 1 line should be parsed.
Maybe you should read a bit about state machines.
Here is a quick approach how I would address the problem:
enum { STATE_HEADER1, STATE_HEADER2, STATE_BODY, STATE_END} state;
int done = 0;
state = STATE_HEADER1;
while (fgets(buffer, MAX_PARSING, fp) && !done) {
if (state == STATE_HEADER1) {
if (strcmp(buffer, "readEveryLine\n") == 0) {
printf("%s", buffer);
state = STATE_HEADER2;
}
else {
printf("Parsing Error 1\n");
done = 1;
}
}
else if (state == STATE_HEADER2) {
if (strcmp(buffer, "{\n") == 0) {
printf("%s", buffer);
state = STATE_BODY;
}
else {
printf("Parsing Error 2\n");
done = 1;
}
}
else if (state == STATE_BODY) {
if (strcmp(buffer, " ") == 0) {
const char *p1 = strstr(buffer, "\"");
const char *pm = strstr(p1, " [m]\"");
const char *pf = strstr(p1, " [f]\"");
char *res;
const char *ptemp;
int is_male;
if (p1 && pf) {
p1 ++;
is_male = 0;
size_t len1 = pf - p1;
res = malloc(len1 + 1);
strcpy(res, p1);
ptemp = pf+3; // point after closing \"
// give res for functionFemale() to work on that string
}
else if (p1 && pm) {
p1 ++;
is_male = 1;
size_t len1 = pm - p1;
res = malloc(len1 + 1);
strcpy(res, p1);
ptemp = pm+3; // point after closing \"
// give res for functionMale() to work on that string
}
else {
done = 1;
printf("Parsing Error 2\n");
}
// Now we have res and is_male holding name and gender.
if (!done)
{
if (strncmp(ptemp, " -> ", 4) == 0) {
// Handle this variant:
// this sign can either exist like this:
// "Bart [m]" -> "Marge [f]";
// Do similar stuff as above for first name
// Get second name + gender
// Also check trailing ';' here
}
else if (strcmp(temp, ";\n") == 0) {
// Handle this variant:
// or like this:
// "Marge [f]";
}
} // found " "
else {
if (strcmp(buffer, "}\n") == 0) {
state = STATE_END;
done = 1;
printf("That's it folks...\n");
}
else {
done = 1;
printf("Parsing Error 3\n");
}
}
}
} // STATE_BODY
} // while (fgets)
if (state == STATE_END) }
// Success. :)
} else {
// Something didn't match.
}
// close file, cleanup, etc.
I did not compile it yet but you should get the idea.

Segfault on fscanf

filenamelists is a struct with two file pointers. merge mergesorts these two fileptrs. I'm getting a segfault on the while(fscanf(filenamelist[0].file1, "%d", &chd) != EOF). I think its because I'm not implementing pthread correctly. Ive been trying to debug forever so any help would be appreciated. tempf is a file ptr to the mergesorted arrays. It is rewinded in the merge function itself.
for(i=0; i<size; i++)
{
if(argc==1)
{
char* tedious2 = (char*) malloc((strlen(argv[i+1]+7))*sizeof(char));
strcpy(tedious2,argv[i+1]);
filenamelist[i].file1 = fopen(strcat(tedious2,".sorted"),"r");
filenamelist[i].file2 = NULL;
filenamelist[i].alone = 1;
free(tedious2);
break;
}
else if(size-1 ==i && size%2 != 0)
{
char* tedious1 = (char*) malloc((strlen(argv[i+1]+7))*sizeof(char));
strcpy(tedious1,argv[i+1]);
filenamelist[i].file1 = fopen(strcat(tedious1,".sorted"),"r");
filenamelist[i].file2 = NULL;
filenamelist[i].alone = 1;
free(tedious1);
}
else
{
char* tedious3 = (char*) malloc((strlen(argv[i+1]+7))*sizeof(char));
strcpy(tedious3,argv[i+1]);
char* tedious4 = (char*) malloc((strlen(argv[i+2]+7))*sizeof(char));
strcpy(tedious4,argv[i+2]);
filenamelist[i].file1 = fopen(strcat(tedious3,".sorted"),"r");
filenamelist[i].file2 = fopen(strcat(tedious4,".sorted"),"r");
filenamelist[i].alone = 0;
free(tedious3);
free(tedious4);
}
}
// pthread_t* threadid2;
// threadid2 = (pthread_t*) malloc(sizeof(pthread_t)*(2*argc));
while(size>=0)
{
i = 0;
pthread_t* threadid2;
threadid2 = (pthread_t*) malloc(sizeof(pthread_t)*size);
for ( ; i<size;i++ )
{
pthread_create(&threadid2[i], NULL, merge, &filenamelist[i]);
}
i = 0;
for ( ; i<size; i++)
{
pthread_join(threadid2[i], tempf);
if (i%2 == 0)
{
filenamelist[i/2].file1 = tempf;
}
else
{
filenamelist[i/2].file2 = tempf;
}
}
zit=0;
truth = 0;
while(zit<z)
{
if(inputFiles[zit] == tempf)
truth = 1;
zit++;
}
if(truth != 1)
{
inputFiles[z] = tempf;
z++;
}
if(size==1)
size = 0;
else if (size % 2 == 0)
size = size/2;
else
size = (size/2)+1;
free(threadid2);
}
int chd = 0;
// if(0!=feof(tempf))
// rewind(tempf);
//rewind(filenamelist[0]->file1);
int finish = 0;
//printf("file 1:%p",tempf);
while(fscanf(filenamelist[0].file1, "%d", &chd) != EOF)
finish++;
rewind(filenamelist[0].file1);
int* finarr = (int*) malloc(finish*sizeof(int));
int xx =0;
for(;fscanf(filenamelist[0].file1, "%d", &chd) != EOF; xx++)
finarr[xx] = chd;
tempf is declared at start of func as FILE* tempf;
char* tedious2 = (char*) malloc((strlen(argv[i+1]+7))*sizeof(char));
Make that:
char *tedious2 = malloc( strlen(argv[i+1]) + strlen(".sorted") + 1 );

Resources