Dev:Source/Data Structures/C Structures and Pointers

提供: wiki
移動先: 案内検索

C Data Structures and Pointers

_".... you need to learn about data structures. These are things like those lists that keep keep showing up in Blender."_ --stiv

Defining Structures

Structures are typically collections of variables and such that we want to keep together. A simple example would be found in source/blender/makesdna/ DNA_meshdata_types.h. Scrolling down to line 67 we see the following code:

typedef struct MCol { 
     char a, r, g, b;
} MCol;

We have declared a structure type called MCol. Inside this struct we have variables or structure members. In this case there are four variables of type char, one each for alpha, red, green, and blue. The MCol after "}" means we just created an instance of MCol called MCol. This last MCol is a variable which every time we use it we can get its alpha, red, green, and blue structure variables.

One thing of note is the typedef statement. Without it every time we wanted to create a new structure variable we would have to do this:

struct MCol MYCol;

Which would create a structure variable named MYCol of type MCol. To simplify we use typedef and save some typing like so:

MCol MYCol;

This is a bit of a simple explanation of typedef and there are other uses for it.

Assigning Structure Members

So now we have this structure and it had structure members. How do we get the data of these members in and out of the structure? Well, there are a couple of ways. The first way is to assign the structure members when declaring the structure like so:

typedef struct MCol { 
     char a, r, g, b;
} MCol = { 255, 0, 128, 255 };

This would assign a=255, r=0, g=128, and b=255 to the variables in the struct.

Option two:

typedef struct MCol { 
     char a, r, g, b;
} MCol;

MCol MCol = { 255, 0, 128, 255 };

Notice this time we assign the member variables and structure variable separate from the structure declaration.

And finally after declaring a structure we can assign values to members by using this syntax:

MCol.a = 255;
MCol.r = 0;
MCol.g = 128;
MCol.b = 255;

Structure Code Example

/* Code listing for BabyBlend */

#include <stdio.h>

int main(void) {
     /* declare structure */    
     typedef struct MVert {
          float co[3];          /* array for vertex coordinates */
          short no[3];          /* array for vertex normals */
          char flag, mat_nr;    /* variables for a flag and material index */
     } MVert;  

     /* create variable of type MVert */ 
     MVert vert; 
     char key_press = '\0'; 
 
     printf("\nWelcome to BabyBlender\n\n");
     printf("To create a vertex press 'V'\n");
     printf("Key: ");
     scanf("%c", &key_press);
     switch (key_press) {
         case 'V': 
         case 'v': 
              /* assign values to the structure's array */
              printf("Enter X coordinate: ");
              scanf("%f", &vert.co[0]); 
              printf("Enter Y coordinate: "); 
              scanf("%f", &vert.co[1]); 
              printf("Enter Z coordinate: "); 
              scanf("%f", &vert.co[2]);

              /* print the values from the structure's array */
              printf("\nYour vertex is is located at\n");
              printf("X: %f\n", vert.co[0]);
              printf("Y: %f\n", vert.co[1]); 
              printf("Z: %f\n", vert.co[2]); 
              break;  
         default: printf("That is not an option\n");
     }
}

So structures are not that scary after all.

Pointers and Variables

_"I'd recommend that anyone who's planning to dig through the source acquaint themselves intimately with C's use of pointers, including the ways that you access elements of pointers to structures; as well as building and incrementing through linked lists; and function pointers."_ --harkyman

A pointer is a variable that holds an address in memory.

A variable can hold data of different types and sizes. Lets say that I wanted to store the alpha, red, green, and blue values of a vetrice in memory using integers. Integers take up two bytes so the following would use 8 bytes:

int a = 255;
int r, g, b;
r = 0;
g = 128;
b = 250;

Declaring Pointers

When creating a pointer you declare it to be a specific type. This type helps tell how much memory is needed. To declare a pointer variable declare the type followed by the variable name with an asterisk prefix like so:

int *alpha;
int *red, *green, *blue;

There are four pointers which hold the address of our variables. At each address we can store an integer. This is where is gets good. We want to store the address of each variable to the pointers. We use the ampersand as a prefix to the variable name when assigning it to a pointer.

alpha = &a;
red = &r;
green = &g;
blue = &b;

Using Pointers

Pointers are used in a number of ways.

     &alpha is used for the address of the pointer.
     alpha is used for the address held by pointer.
     *alpha is used for the value held at the address stored in the pointer.

Nice stuff. Just remember there is a difference between variables and pointers. When adding one to a variable we add to the value stored in the variable. When adding one to the pointer, we add to the address of the pointer. So if our color pointers are all in order in memory, by adding one to the pointer alpha I would get the address of red.

     alpha +=1;

If I add four to alpha I would get the address of the next alpha. This is because a pointer of type integer can only hold the address of an integer. In addition to this the pointer also knows that it is 2 bytes long. To add one to the variable b using a pointer:

*blue += 1;

Now blue is 251. This is pretty powerful stuff.

Pointer Code Example

/* code listing for BabyBlend2 */

#include <stdio.h>

int main(void) {
     /* declare some variables of type int*/ 
     int a, r, g, b;
     /* declare pointers to type int */ 
     int *alpha, *red, *green, *blue;
     /* assign the addresses of the variables to the pointers */ 
     alpha = &a; red = &r; green = &g; blue = &b;  
     /* assign values to the variables using pointers */ 
     *alpha = 255;
     *red = 0;
     *green = 128;
     *blue = 250;  
     
     /* print alpha data */ 
     printf("\nAddress of pointer alpha %p\n", &alpha); 
     printf("Address held by pointer alpha %p\n", alpha); 
     printf("Value at address held by alpha %d\n", *alpha); 
     
     /* print red data */ 
     printf("\nAddress of pointer red %p\n", &red);
     printf("Address held by pointer red %p\n", red);
     printf("Value at address held by red %d\n", *red);

     *alpha -= 1;
     printf("\n*alpha -= 1\n");
     printf("Address of pointer alpha %p\n", &alpha); 
     printf("Address held by pointer alpha %p\n", alpha);
     printf("Value at address held by alpha %d\n", *alpha);
     printf("\nNotice value at address held by alpha is one less\n");

     alpha += 1;
     printf("\nalpha += 1\n");
     printf("Address of pointer alpha %p\n", &alpha);
     printf("Address held by pointer alpha %p\n", alpha);
     printf("Value at address held by alpha %d\n", *alpha);
     printf("\nNotice alpha now points to address held by red\n");
}

Pointers to Structures

Let's create a structure called vert and then create a pointer and finally point to the structure.

     MVert vert;            /* creates structure variable "vert" */
     MVert *vert_point;     /* creates pointer to structure of type MVert */
     vert_point = &vert;    /* assign address of variable vert to pointer */

Accessing Structure Data using Pointers

We access the structure variables with the pointer using this syntax.

     (*vert_point).mat_nr = 1;               /* assigns 1 to mat_nr of structure */
     printf("X co %f", (*vert_point).co[0]); /* print x coordinate */

We can simplify the readability of the code using a different syntax.

     vert_point->mat_nr = 1;              /* assigns 1 to mat_nr of structure */
     printf("X co %f", vert_point->co[0]); /* print x coordinate */

Pointer to Structures Code Example

In this example we access the structure variables with a pointer to the structure. Compare this to the code in part 1.

/* Pointer to Structure Code Listing */

#include <stdio.h>

int main(void) {
     /* declare structure */
     typedef struct MVert { 
          float   co[3];      /* array for vertex coordinates */
          short   no[3];      /* array for vertex normals */
          char flag, mat_nr;  /* variables for a flag and material index */
     } MVert;
 
     MVert vert;        /* create variable of type MVert */
     MVert *vert_point; /* create pointer to type MVert */ 
     char key_press = '\0';
 
     /* assign structure address to pointer */ 
     vert_point = &vert;  
     
     printf("\nWelcome to BabyBlender\n\n"); 
     printf("To create a vertex press 'V'\n"); 
     printf("Key: "); 
     scanf("%c", &key_press);
     switch (key_press) {
          case 'V': 
          case 'v': 
               /* assign values to the structure's array */
               printf("Enter X coordinate: ");
               scanf("%f", &(*vert_point).co[0]); 
               printf("Enter Y coordinate: "); 
               scanf("%f", &(*vert_point).co[1]); 
               printf("Enter Z coordinate: "); 
               scanf("%f", &(*vert_point).co[2]); 

               /* print the values from the structure's array */
               printf("\nYour vertex is located at\n");
               printf("X: %f\n", vert_point->co[0]); 
               printf("Y: %f\n", vert_point->co[1]); 
               printf("Z: %f\n", vert_point->co[2]); 
          break;  
          default: printf("That is not an option\n");
      }
}


-- DeveloperWikiStephenHughes - 27 Apr 2005