Hello Everyone,

I'm a problem with a recursive C function. Before I explain the functionality of the code, I'd like to give a brief explination of what I'm trying to do. I'm working on a general tree data type which represents entities, each of which has a list -array- of arguments. What I'm trying to do is to traverse the tree in a recursive manner and retrieve and populated a new array with the entities and their arguments. The problem is as follows:
As I retrieve the information and print it right away I have no problem, but when I attempt to print the new array contents (using print key function) after the recursive function (Traverse_sem) exists, I not only get a runtime error, but the little cotents printed are wrong.
So I'm guessing either the array index isn't being updated as I populate the new data type; meaning it stores, prints and overwrites, thus the correct printout during population process, OR the array index is being updated but something related with the datatype definition is wrong causing this problem. I hope that I have explained the problem in a clear manner, I'd appreicate all the help I can get.

Thanks in Advance,
Layla.

/ Defining Principal known keys table

static struct ky {
       char *ID1;
       char *ID2;
       int  Inv;
       };

typedef struct ky  Keys;

struct prnc {
       char *ID;
       int  nk;
       Keys kys[0];
       };

static struct prnc principal_know_key[0];


//********************************************************
// Traverse the tree to check a number of constraints
//********************************************************

void traverse_sem(Ast a){
	Ast *t;
	int i;
	int n;
	int sflag;
	int rflag;
	char *message_sr_id;
	char *message_rc_id;
	    
    
    switch(NKIND(a))
    {
		case PROTOCOL: 
			t = PROTOCOL_PRINCIPALS(a);
			num_principals = PROTOCOL_NB_PRINCIPALS(a);
			fprintf(outS,"\tNumber: %d\n", num_principals);
			// Traverse Principals
                                      for (i=0;i<num_principals;i++) 
				traverse_sem(t[i]);
			// Ensure that at least two principals are present
                                       fprintf(outS,"\tViolations: ");
                                      if (principal_counter < 2 )
                                         printf("Yes \n\t\t Less than two principals are   declared.\n\n");
                                     else
                                     if (num_principals > principal_counter)
                                         fprintf(outS,"\nExcessive declaration of principals");
                                     else
                                         fprintf(outS," No \n\n");
     
			// Traverse Messages
			fprintf(outS,"Messages:\n");
                                      num_messages = PROTOCOL_NB_MESSAGES(a);
			fprintf(outS,"\tNumber: %d\n", num_messages);
			t = PROTOCOL_MESSAGES(a);
			for (i=0;i<num_messages;i++)
				traverse_sem(t[i]);
				
			     
            break;
		
        case PRINCIPAL:
            principals_list[principal_counter]= PRINCIPAL_ID(a); 
            principal_know_key[principal_counter].ID = PRINCIPAL_ID(a);
            printf("\n Principal Name: %s", principal_know_key[principal_counter].ID); //delete here
            fprintf(outS,"\tPrincipal %d : %s \n", principal_counter+1, principals_list[principal_counter]);
            t = PRINCIPAL_KNOW(a);
            n = PRINCIPAL_NB_KNOWS(a);
            principal_know_key[principal_counter].nk= n;
            for (i=0;i<n;i++)
          		traverse_sem(t[i]);
			key_counter =0;
			++principal_counter; 
			break;
					   
		case KEY:
             printf("\n\t Key # %d", key_counter+1);
             principal_know_key[principal_counter].kys[key_counter].ID1 = KEY_ID1(a);
             printf("\n\t\t\t ID1 : %s", principal_know_key[principal_counter].kys[key_counter].ID1);
             principal_know_key[principal_counter].kys[key_counter].ID2 = KEY_ID2(a);
             printf("\n\t\t\t ID2 : %s", principal_know_key[principal_counter].kys[key_counter].ID2);
             principal_know_key[principal_counter].kys[key_counter].Inv = KEY_INV(a);
             printf("\n\t\t\t Inv : %d", principal_know_key[principal_counter].kys[key_counter].Inv);
             ++key_counter;
        break;
             
        
        case MESSAGE:
            t = MESSAGE_SENT_DATA(a);
	n = MESSAGE_NB_SENT_DATA(a);
            ++message_counter;
            fprintf(outS,"\n\tMessage %d\n", message_counter);
            
            message_sr_id = MESSAGE_SENDER_ID(a);
            fprintf(outS,"\t\tSender: %s\n", message_sr_id);
            message_rc_id = MESSAGE_RECEIVER_ID(a);
            fprintf(outS,"\t\tReceiver: %s\n",message_rc_id);
            
            fprintf(outS,"\t\tViolations: ");
          
            //Check for sender validity
            sflag = PrincipalPresense("Sender", message_sr_id,0);
            
            //Check for reciever validity            
            rflag = PrincipalPresense("Receiver", message_rc_id,sflag);
            
            if ((sflag ==0) && (rflag == 0))
               fprintf(outS," No \n\n");
            
            for (i=0;i<n;i++){
	  traverse_sem(t[i]);
                }   
            		
	break;
	
    }
}


/ A test function to display the contents of the array principal_know_key

void printkey(){
     int i;
     int j;
     int numkeys;
     
     for(i =0; i < principal_counter ; i++)
     {
           printf("\n Principal Name: %s", principal_know_key[i].ID);
           numkeys = principal_know_key[i].nk;
           printf("\n\t Number of known keys: %d", numkeys);
           
           for (j=0; j < numkeys ; j++)
               {
                     printf("\n\t\t Key # %d: ", j+1);
                     printf("\n\t\t\t ID1 : %s", principal_know_key[i].kys[j].ID1);
                     printf("\n\t\t\t ID2 : %s", principal_know_key[i].kys[j].ID2);
                     printf("\n\t\t\t Inv : %d", principal_know_key[i].kys[j].Inv);
                }
     }
}

Recommended Answers

All 13 Replies

Do you have a small, but complete, example? I cannot compile the code you have posted, and this makes offering assistance much more difficult.

Dave,
I appreciate your attempt to help, unfrotunately the entire code is scattered over 10 files! therefore I had to post the segments of code related to the problem. So my question is as follows,
1- from your experience, do you know of a reason causing a data structure to store data but then lose it?! cause when I print the cotents as I store the data things are OK, but when I attempt to print the contents of the array after the recursive function exists, I'm getting the run time error + it seems the array doesn't hold the data any longer.
2- My 2nd guess is that the index of the array isn't being updated, meaning as I'm storing and printing correctly, the next item of data overwrites the previous one as the index does not increase, again I can't see why this is happening, the logic seems correct to me.

case PRINCIPAL:
            principals_list[principal_counter]= PRINCIPAL_ID(a); 
            principal_know_key[principal_counter].ID = PRINCIPAL_ID(a);
            printf("\n Principal Name: %s", principal_know_key[principal_counter].ID); //delete here
            fprintf(outS,"\tPrincipal %d : %s \n", principal_counter+1, principals_list[principal_counter]);
            t = PRINCIPAL_KNOW(a);
            n = PRINCIPAL_NB_KNOWS(a);
            principal_know_key[principal_counter].nk= n;
            for (i=0;i<n;i++)
          		traverse_sem(t[i]);
			key_counter =0;
			++principal_counter; 
			break;
					   
		case KEY:
             printf("\n\t Key # %d", key_counter+1);
             principal_know_key[principal_counter].kys[key_counter].ID1 = KEY_ID1(a);
             printf("\n\t\t\t ID1 : %s", principal_know_key[principal_counter].kys[key_counter].ID1);
             principal_know_key[principal_counter].kys[key_counter].ID2 = KEY_ID2(a);
             printf("\n\t\t\t ID2 : %s", principal_know_key[principal_counter].kys[key_counter].ID2);
             principal_know_key[principal_counter].kys[key_counter].Inv = KEY_INV(a);
             printf("\n\t\t\t Inv : %d", principal_know_key[principal_counter].kys[key_counter].Inv);
             ++key_counter;
        break;

3- Would you by any chance know how to use the debugging feature in the Dev - C++ compiler? I couldn't figure it out and I think if I use it i'd spot the source of error.

Again Dave thanks alot for your help.
Have a good one,
Layla.

unfrotunately the entire code is scattered over 10 files! therefore I had to post the segments of code related to the problem.

With larger sets of code, either try cutting out what is known to be working -- using #if 0 ... #endif, for example; or try recreating a new side project and begin adding in the desired (but buggy) code until it breaks.

1- from your experience, do you know of a reason causing a data structure to store data but then lose it?!

Yes, I've seen such things. It seems especially that I've seen such behavior when using recursion.

I'm getting the run time error + it seems the array doesn't hold the data any longer.

For a runtime error, I'd suspect wandering off the array bounds with or without the help of a pointer.

2- My 2nd guess is that the index of the array isn't being updated, meaning as I'm storing and printing correctly, the next item of data overwrites the previous one as the index does not increase, again I can't see why this is happening, the logic seems correct to me.

I like to use tools such as lint to help with a static analysis of the code. Unfortunately, it won't do much on piecepart fragments.

Crank up the error/warning level, i.e., -Wall -ansi -pedantic, to see if that can help pick out other things; data types and wrong format specifiers may do bad things too.

3- Would you by any chance know how to use the debugging feature in the Dev - C++ compiler? I couldn't figure it out and I think if I use it i'd spot the source of error.

I've been meaning to, but haven't gone there yet.

Dave,
Thanks for your prompt comment, I really appreciate it.

With larger sets of code, either try cutting out what is known to be working -- using #if 0 ... #endif, for example; or try recreating a new side project and begin adding in the desired (but buggy) code until it breaks.

Actually I don't think that would help, as I'm sure that the problem is related to array population process, hence I know what segment of code needs to be debugged.

Quote:
Originally Posted by Layla_2401

1- from your experience, do you know of a reason causing a data structure to store data but then lose it?!

Yes, I've seen such things. It seems especially that I've seen such behavior when using recursion.

Would you know how to tackle such problem? I have declared the array and the two index variables (key_counter and principal_counter) as static variables but that doesn't seem to make much of a difference.

Again Dave thank you so much for your help, its highly appreciated.
Layla.

static struct prnc principal_know_key[0];

Was this a typo? Or could you expand on your intentions here a little more?

Actually no its not a typo, assuming you're referring to the [0] part. I declared it this way cause the number of principals declared varies from one run to another. I didn't think this would cause a problem since I have another array in the program defined as:

static char *principals[0];

and this declaration worked just fine even as it is populated using a recursive function.
So, last night I've tried something like this:

static struct prnc *principal_know_key[0];

and addressed this data structure in the program as follows:

(*principal_know_key).ID

... etc

Though I was able to compile, I instantly got a run-time error and the program gave no results what so ever, unlike the previous run-time error which occured only when attempting to print.

So, what do you think?

As always Dave your help is deeply appreciated, thanks.

Actually no its not a typo, assuming you're referring to the [0] part.

Though I was able to compile, I instantly got a run-time error and the program gave no results what so ever, unlike the previous run-time error which occured only when attempting to print.

So, what do you think?

I don't think it should compile. I get syntax errors in BC5.5 as both C and C++, and lint does not care for it. So if it does compile, you may be using some nonstandard extension.

If your intent is to declare a pointer such that you can allocate memory for a number of items determined at runtime, I think that is what you should do. Perhaps include the memory allocation code, and certainly keep track of the indexing: i.e., an array of 10 may be indexed from 0-9 only.

Yes you're right, its defined that way cause the number of array elements is only known at run-time, BUT! I'm not allocating array space explicitly, I'm simply increasing the index as shown in the code above.
I've even tried something else like declaring the array as:

static struct prnc principal_know_key[5];

but I still got the same error. NOTHING seems to be working!

BUT! I'm not allocating array space explicitly, I'm simply increasing the index as shown in the code above.

Ah, going back to this, I think I may see something.

do you know of a reason causing a data structure to store data but then lose it?!

If you are not properly allocating memory, you may be getting "lucky" when you are printing it immediately. That is, you may be writing to memory you don't own, but there is no immediate crash.

The bit about recursion makes me think you may be writing to some "stack" space and printing it; then "losing" this memory when the "stack" is freed up on the recursion.

Again, it's difficult to debug the fragment like this. Another thing that may need closer scrutiny is this.

void traverse_sem(Ast a){
	Ast *t;
	// ...
    
    switch(NKIND(a))
    {
		case PROTOCOL: 
			t = PROTOCOL_PRINCIPALS(a);
			// ...
                                      for (i=0;i<num_principals;i++) 
				traverse_sem(t[i]);
			// t may be different here from what is expected

[edit]The following is an attempt to demonstrate something or other.

#include <stdio.h>
#include <string.h>

char *recurse(char *response)
{
   printf("DEBUG1: response = \"%s\"\n", response);
   if (!*response)
   {
      char buffer[10];
      response = buffer;
      strcpy(response, "Hello");
   }
   else
   {
      recurse(response + 1);
   }
   printf("DEBUG2: response = \"%s\"\n", response);
   return response;
}

int main(void)
{
   char text[10] = "Original";
   puts(text);
   puts(recurse(text));
   return 0;
}

/* my output
Original
DEBUG1: response = "Original"
DEBUG1: response = "riginal"
DEBUG1: response = "iginal"
DEBUG1: response = "ginal"
DEBUG1: response = "inal"
DEBUG1: response = "nal"
DEBUG1: response = "al"
DEBUG1: response = "l"
DEBUG1: response = ""
DEBUG2: response = "Hello"
DEBUG2: response = "l"
DEBUG2: response = "al"
DEBUG2: response = "nal"
DEBUG2: response = "inal"
DEBUG2: response = "ginal"
DEBUG2: response = "iginal"
DEBUG2: response = "riginal"
DEBUG2: response = "Original"
Original
*/

Dave,
given that the following is what I need,

static struct ky {
       char *ID1;
       char *ID2;
       int  Inv;
       };

typedef struct ky  Keys;

struct prnc {
       char *ID;
       int  nk;
       Keys kys[0];
       };

static struct prnc principal_know_key[0];

1- can you suggest any alteration to this data structure,
2- how would you go about array allocation
3- Would array population code need to be changed?
4- Must I use a return value for function loadkey() instead of void, and if so, how (what data structure)?! cause I have already tried declaring the function as:

struct prnc * loadkeys(Ast A)

and instead of using break at the end of each swtich case, I used:

return (*principal_know_key[i]);

of course, that didn't work either.

There is much I don't know: an example of the expected input and output, what an Ast is, etc. So I'll come up with another canned example. It's rather icky, but it shows the pains of allocating memory, which I think you need to do for all your pointers. Alternatively, if you used arrays in the structures, life would be much easier.

5
Identifier text
Id1-1
Id2-1
1
Id1-2
Id2-2
2
Id1-3
Id2-3
3
Id1-4
Id2-4
4
Id1-5
Id2-5
5

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct ky
{
   char *ID1;
   char *ID2;
   int  Inv;
};

typedef struct ky  Keys;

struct prnc
{
   char *ID;
   int  nk;
   Keys *kys;
};

static struct prnc principal_know_key;

int loadkeys(const char *filename)
{
   char line[80];
   int i;
   FILE *file = fopen(filename, "r");
   if ( !file )
   {
      return -1; /* error */
   }
   if ( !fgets(line, sizeof line, file) )
   {
      return -2; /* error */
   }
   line[strcspn ( line, "\n" )] = '\0';
   if ( sscanf(line, "%d", &principal_know_key.nk) != 1 )
   {
      return -3; /* error */
   }
   principal_know_key.kys = malloc(principal_know_key.nk * sizeof *principal_know_key.kys);
   if ( !principal_know_key.kys )
   {
      return -4; /* error */
   }
   if ( !fgets(line, sizeof line, file) )
   {
      return -5; /* error */
   }
   line[strcspn ( line, "\n" )] = '\0';
   principal_know_key.ID = malloc(strlen(line) + 1);
   if ( !principal_know_key.ID )
   {
      return -6; /* error */
   }
   strcpy(principal_know_key.ID, line);
   for ( i = 0; i < principal_know_key.nk; ++i )
   {
      if ( !fgets(line, sizeof line, file) )
      {
         return -7; /* error */
      }
      line[strcspn ( line, "\n" )] = '\0';
      principal_know_key.kys[i].ID1 = malloc(strlen(line) + 1);
      if ( !principal_know_key.kys[i].ID1 )
      {
         return -8; /* error */
      }
      strcpy(principal_know_key.kys[i].ID1, line);

      if ( !fgets(line, sizeof line, file) )
      {
         return -9; /* error */
      }
      line[strcspn ( line, "\n" )] = '\0';
      principal_know_key.kys[i].ID2 = malloc(strlen(line) + 1);
      if ( !principal_know_key.kys[i].ID2 )
      {
         return -10; /* error */
      }
      strcpy(principal_know_key.kys[i].ID2, line);

      if ( !fgets(line, sizeof line, file) )
      {
         return -11; /* error */
      }
      if ( sscanf(line, "%d", &principal_know_key.kys[i].Inv) != 1 )
      {
         return -12; /* error */
      }
   }
   fclose(file);
   return 0;
}

void showme(void)
{
   int i;
   printf("principal_know_key.nk = %d\n", principal_know_key.nk);
   printf("principal_know_key.ID = \"%s\"\n", principal_know_key.ID);
   for ( i = 0; i < principal_know_key.nk; ++i )
   {
      printf("principal_know_key.kys[%d].ID1 = \"%s\"\n", i, principal_know_key.kys[i].ID1);
      printf("principal_know_key.kys[%d].ID2 = \"%s\"\n", i, principal_know_key.kys[i].ID2);
      printf("principal_know_key.kys[%d].Inv = %d\n", i, principal_know_key.kys[i].Inv);
   }
}

void cleanup(void)
{
   int i;
   for ( i = 0; i < principal_know_key.nk; ++i )
   {
      free(principal_know_key.kys[i].ID2);
      free(principal_know_key.kys[i].ID1);
   }
   free(principal_know_key.kys);
}

int main(void)
{
   if ( loadkeys("file.txt") == 0 )
   {
      showme();
      cleanup();
   }
   return 0;
}

principal_know_key.nk = 5
principal_know_key.ID = "Identifier text"
principal_know_key.kys[0].ID1 = "Id1-1"
principal_know_key.kys[0].ID2 = "Id2-1"
principal_know_key.kys[0].Inv = 1
principal_know_key.kys[1].ID1 = "Id1-2"
principal_know_key.kys[1].ID2 = "Id2-2"
principal_know_key.kys[1].Inv = 2
principal_know_key.kys[2].ID1 = "Id1-3"
principal_know_key.kys[2].ID2 = "Id2-3"
principal_know_key.kys[2].Inv = 3
principal_know_key.kys[3].ID1 = "Id1-4"
principal_know_key.kys[3].ID2 = "Id2-4"
principal_know_key.kys[3].Inv = 4
principal_know_key.kys[4].ID1 = "Id1-5"
principal_know_key.kys[4].ID2 = "Id2-5"
principal_know_key.kys[4].Inv = 5

Dave, you're an angel! I'll give it a try and get back to you.

Dave! check this out:

I defined both arrays (inner and outter) as [5] and guess what?? IT WORKED! :D
Dave you're the best! thank you sooooo much! How can I ever repay you??
May God bless your soul :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.