Is it bad to refer to access array elements via pointer arithmetic instead of the [] operator?

Loading...

Is it bad to refer to access array elements via pointer arithmetic instead of the [] operator?

I've just started learning to program in C, and to improve my understanding of pointers and arrays, I tried to refer to the elements of an array without creating any pointer at all:
for(k1 = 0; k1 < ROW; k1++){
    for(k2 = 0; k2 < COLUMN; k2++){

        array[k1][k2] = k1*COLUMN + k2 + 1;

        printf("[%d][%d] = %d\n", k1, k2, *(array[k1] + k2));

    }
}

The entire code compiles and runs flawlessly.
I imagine having to create a pointer for every single array in a big source code seems to be highly inefficient.
So, rather than having the address of an array stored and retrieved by using a pointer, is it a bad programming practice to use the address of the array directly, as shown above?

Solutions/Answers:

Answer 1:

It's "bad" only to the extent that's less readable. a[x] is the same thing as *(a+x), so there's no difference in efficiency or behavior (in fact, x[a] will also work). It's just that a[x] is usually a lot more intuitive to us humans.

But that's not to say readability isn't a big deal. To see how big, think about how you would "read" these two expressions if you saw them in code:

  • *(a+x) = "The thingy pointed to by the sum of pointer a and integer x"
  • a[x] = "The xth member of array a"

Similarly, when you need to refer to the address of an array element:

  • (a+x) = "The sum of pointer a and integer x"
  • &a[x] = "The address of the xth member of array a"

Most of the time, the [] versions are just easier to understand when you're looking at non-trivial code operating on several different arrays (especially arrays of arrays). That's why the [] operator exists in the first place.

P.S. Doing this sort of thing strictly as a learning exercise is a very good idea. It's important to understand that arrays really are just pointers and offsets.

Answer 2:

Yes, it's bad practice, but not for inefficiency reasons.

Array operator uses pointer arithmetric under the hood, so they're equally efficient.

Problem with pointer arithmetric is that it's very error prone and harder to read.

Rule of thumb: Don't use pointer arithmetric unless you have to.

Answer 3:

Cool your learning c, you just discovered one of c little tongue twisters. You are not doing pointer arithmetic on an array, but an array of pointers. Doing pointer arithmetic on arrays is not possible. An array decays to a pointer but is not a pointer type it self.
What you my have (see comment by cmaster) is

int *array[]; //This is a array to pointers of type *int. 

array[k1] + k2; //This is pointer arithmetic on one pointer stored in the array  

Dereferencing this pointer gives the value your just calculated pointer, points to. There is generally no point in doing what you are doing. But you can linearised the array and then a stride in it, like this.

int array[y_dim*x_dim]; 
int index = x_dim*y + x; 
array[index]; //Gives you the element in x, y!

Stride her is x_dim.
Hope my answer is clarifying!

References

Loading...

How do I append multiple taxonomies to the URL?

Loading...

How do I append multiple taxonomies to the URL?

Multiple taxonomies in URL
How does one append multiple taxonomies to the URL having the following:


Post Type: products
Taxonomy: product_type
Taxonomy: product_brand



Adding new product and selecting type and brand for this product: 
When adding a new product, there are two taxonomy boxes (product_type and product_brand). Let's call this new post Test Product 1. The first thing we want to do is tick what type of product I'm dealing with, let's say cell-phones. Next, I want to tick what brand the product belongs to, let's say samsung. 
Now "Test Product 1" is associated with the type "cell-phones" and the brand "samsung".
The desired end result is:

/products 
  » View all custom posts
/products/cell-phones 
  » View all custom posts with the taxonomy cell-phones
/product/cell-phones/samsung/ 
  » View all custom posts where the taxonomy is cell-phones AND samsung
/products/cell-phones/samsung/test-product-1 
  » View the product (single custom post)


The question
How would one make this possible? My initial thought was using one taxonomy, having "cell-phones" as the parent term of "samsung". Actually appending the taxonomy and its terms was not so tough. But it led to a lot of other issues, some well known, some not so much. Anyway it doesn't work like that as it gives 404 issues and WP won't allow certain things. 
WP.org » taxonomy-archive-template
This lead me to having rethought the structure, having to leave taxonomies and its terms and I thought; why not create a 2nd taxonomy, and associate the post type with it and append that to the url? 
Good question indeed, but how?

Solutions/Answers:

Answer 1:

This is certainly possible by utilizing some rewrite rules of your own to some extent. The WP_Rewrite API exposes functions that allow you to add rewrite rules (or ‘maps’) to convert a request to a query.

There are prerequisites to writing good rewrite rules, and the most important one is basic regular expression comprehension. The WordPress Rewrite engine uses regular expressions to translate parts of a URL to queries to get posts with.

This is a short and good tutorial on PHP PCRE (Perl compatible regular expressions).

So, you’ve added two taxonomies, let’s assume their names are:

  • product_type
  • product_brand

We can use these in queries like so:

get_posts( array(
    'product_type' => 'cell-phones',
    'product_brand' => 'samsung'
) );

The query would be ?product_type=cell-phones&product_brand=samsung. If you type that as your query you will get a list of Samsung phones. To rewrite /cell-phones/samsung into that query a rewrite rule must be added.

add_rewrite_rule() will do this for you. Here’s an example of what your rewrite rule might look like for the above case:

add_rewrite_rule( '^products/([^/]*)/([^/]*)/?',
    'index.php?product_type=$matches[1]&product_brand=$matches[2]',
    'top' );

You will need to flush_rewrite_rules() as soon as you’ve added the rewrite rule to save it to the database. This is done only once, there is no need to do this with every request, once a rule is flushed its there. To remove it simply flush without the added rewrite rule.

If you want to add pagination you can do so by doing something like:

add_rewrite_rule( '^products/([^/]*)/([^/]*)/(\d*)?',
    'index.php?product_type=$matches[1]&product_brand=$matches[2]&p=$matches[3]',
    'top' );

Answer 2:

The end result

This is what I came up with partially using bits and pieces from all answers I’ve got:

/**
 * Changes the permalink setting <:> post_type_link
 * Functions by looking for %product-type% and %product-brands% in the URL
 * 
  * products_type_link(): returns the converted url after inserting tags
  *
  * products_add_rewrite_rules(): creates the post type, taxonomies and applies the rewrites rules to the url
 *
 *
 * Setting:         [ produkter / %product-type%  / %product-brand% / %postname% ]
 * Is actually:     [ post-type / taxonomy        /  taxonomy       / postname   ]
 *                   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 * Desired result:  [ products  / cellphones      / apple           / iphone-4   ]
 */

    // Add the actual filter    
    add_filter('post_type_link', 'products_type_link', 1, 3);

    function products_type_link($url, $post = null, $leavename = false)
    {
        // products only
        if ($post->post_type != 'products') {
            return $url;
        }

        // Post ID
        $post_id = $post->ID;

        /**
         * URL tag <:> %product-type%
         */
            $taxonomy = 'product-type';
            $taxonomy_tag = '%' . $taxonomy . '%';

            // Check if taxonomy exists in the url
            if (strpos($taxonomy_tag, $url) <= 0) {

                // Get the terms
                $terms = wp_get_post_terms($post_id, $taxonomy);

                if (is_array($terms) && sizeof($terms) > 0) {
                    $category = $terms[0];
                }

                // replace taxonomy tag with the term slug » /products/%product-type%/productname
                $url = str_replace($taxonomy_tag, $category->slug, $url);
            }

        /** 
         * URL tag <:> %product-brand%
         */
        $brand = 'product-brand';
        $brand_tag = '%' . $brand . '%';

        // Check if taxonomy exists in the url
        if (strpos($brand_tag, $url) < 0) {
            return $url;
        } else { $brand_terms = wp_get_post_terms($post_id, $brand); }

        if (is_array($brand_terms) && sizeof($brand_terms) > 0) {
            $brand_category = $brand_terms[0];
        }

        // replace brand tag with the term slug and return complete url » /products/%product-type%/%product-brand%/productname
        return str_replace($brand_tag, $brand_category->slug, $url);

    }

    function products_add_rewrite_rules() 
    {
        global $wp_rewrite;
        global $wp_query;

        /**
         * Post Type <:> products
         */

            // Product labels
            $product_labels = array (
                'name'                  => 'Products',
                'singular_name'         => 'product',
                'menu_name'             => 'Products',
                'add_new'               => 'Add product',
                'add_new_item'          => 'Add New product',
                'edit'                  => 'Edit',
                'edit_item'             => 'Edit product',
                'new_item'              => 'New product',
                'view'                  => 'View product',
                'view_item'             => 'View product',
                'search_items'          => 'Search Products',
                'not_found'             => 'No Products Found',
                'not_found_in_trash'    => 'No Products Found in Trash',
                'parent'                => 'Parent product'
            );

            // Register the post type
            register_post_type('products', array(
                'label'                 => 'Products',
                'labels'                => $product_labels,
                'description'           => '',
                'public'                => true,
                'show_ui'               => true,
                'show_in_menu'          => true,
                'capability_type'       => 'post',
                'hierarchical'          => true,
                'rewrite'               => array('slug' => 'products'),
                'query_var'             => true,
                'has_archive'           => true,
                'menu_position'         => 5,
                'supports'              => array(
                                            'title',
                                            'editor',
                                            'excerpt',
                                            'trackbacks',
                                            'revisions',
                                            'thumbnail',
                                            'author'
                                        )
                )
            );

        /**
         * Taxonomy <:> product-type
         */
            register_taxonomy('product-type', 'products', array(
                'hierarchical' => true, 
                'label' => 'Product Types', 
                'show_ui' => true, 
                'query_var' => true, 
                'rewrite' => array('slug' => 'products/types'),
                'singular_label' => 'Product Types') 
            );

        /**
         * Taxonomy <:> product-type
         */
            register_taxonomy('product-brand', 'products', array(
                'hierarchical' => true, 
                'label' => 'Product Brands', 
                'show_ui' => true, 
                'query_var' => true, 
                'rewrite' => array('slug' => 'product/brands'),
                'singular_label' => 'Product Brands') 
            );

            $wp_rewrite->extra_permastructs['products'][0] = "/products/%product-type%/%product-brand%/%products%";

            // flush the rules
            flush_rewrite_rules();
    }

    // rewrite at init
    add_action('init', 'products_add_rewrite_rules');

Some thoughts:

This does work. Although you’re ‘required’ to assign both taxonomies to each post or the URL will have a trailing '/' » '/products/taxonomy//postname'.
Since I’m going to assign both taxonomies to all my procuts, having a type and a brand, this code seems to be working for my needs. If anyone has any suggestions or improvesments feel free to reply!

Answer 3:

Check this way, it still have some bugs with brand archive

http://pastebin.com/t8SxbDJy

add_filter('post_type_link', 'products_type_link', 1, 3);

function products_type_link($url, $post = null, $leavename = false)
{
// products only
    if ($post->post_type != self::CUSTOM_TYPE_NAME) {
        return $url;
    }

    $post_id = $post->ID;

    $taxonomy = 'product_type';
    $taxonomy_tag = '%' . $taxonomy . '%';

    // Check if exists the product type tag
    if (strpos($taxonomy_tag, $url) < 0) {
        // replace taxonomy tag with the term slug: /products/%product_type%/samsumng/productname
        $url = str_replace($taxonomy_tag, '', $url);
    } else {
        // Get the terms
        $terms = wp_get_post_terms($post_id, $taxonomy);

        if (is_array($terms) && sizeof($terms) > 0) {
            $category = $terms[0];
            // replace taxonomy tag with the term slug: /products/%product_type%/samsumng/productname
            $url = str_replace($taxonomy_tag, $category->slug, $url);
        }
        }

    /* 
     * Brand tags 
     */
    $brand = 'product_brand';
    $brand_tag = '%' . $brand . '%';

    // Check if exists the brand tag 
    if (strpos($brand_tag, $url) < 0) {
        return str_replace($brand_tag, '', $url);
    }

    $brand_terms = wp_get_post_terms($post_id, $brand);

    if (is_array($brand_terms) && sizeof($brand_terms) > 0) {
        $brand_category = $brand_terms[0];
    }

    // replace brand tag with the term slug: /products/cell-phone/%product_brand%/productname 
    return str_replace($brand_tag, $brand_category->slug, $url);
}

function products_add_rewrite_rules() 
{
global $wp_rewrite;
global $wp_query;

register_post_type('products', array(
    'label' => 'Products',
    'description' => 'GVS products and services.',
    'public' => true,
    'show_ui' => true,
    'show_in_menu' => true,
    'capability_type' => 'post',
    'hierarchical' => true,
    'rewrite' => array('slug' => 'products'),
    'query_var' => true,
    'has_archive' => true,
    'menu_position' => 6,
    'supports' => array(
        'title',
        'editor',
        'excerpt',
        'trackbacks',
        'revisions',
        'thumbnail',
        'author'),
    'labels' => array (
        'name' => 'Products',
        'singular_name' => 'product',
        'menu_name' => 'Products',
        'add_new' => 'Add product',
        'add_new_item' => 'Add New product',
        'edit' => 'Edit',
        'edit_item' => 'Edit product',
        'new_item' => 'New product',
        'view' => 'View product',
        'view_item' => 'View product',
        'search_items' => 'Search Products',
        'not_found' => 'No Products Found',
        'not_found_in_trash' => 'No Products Found in Trash',
        'parent' => 'Parent product'),
    ) 
);

register_taxonomy('product-categories', 'products', array(
    'hierarchical' => true, 
    'label' => 'Product Categories', 
    'show_ui' => true, 
    'query_var' => true, 
    'rewrite' => array('slug' => 'products'),
    'singular_label' => 'Product Category') 
);

$wp_rewrite->extra_permastructs['products'][0] = "/products/%product_type%/%product_brand%/%products%";

    // product archive
    add_rewrite_rule("products/?$", 'index.php?post_type=products', 'top');

    /* 
     * Product brands
     */
    add_rewrite_rule("products/([^/]+)/([^/]+)/?$", 'index.php?post_type=products&product_brand=$matches[2]', 'top');
    add_rewrite_rule("products/([^/]+)/([^/]+)/page/([0-9]{1,})/?$", 'index.php?post_type=products&product_brand=$matches[2]&paged=$matches[3]', 'top');

    /*
     * Product type archive
     */
    add_rewrite_rule("products/([^/]+)/?$", 'index.php?post_type=products&product_type=$matches[1]', 'top');    
    add_rewrite_rule("products/([^/]+)/page/([0-9]{1,})/?$", 'index.php?post_type=products&product_type=$matches[1]&paged=$matches[1]', 'bottom'); // product type pagination

    // single product
    add_rewrite_rule("products/([^/]+)/([^/]+)/([^/]+)/?$", 'index.php?post_type=products&product_type=$matches[1]&product_brand=$matches[2]&products=$matches[3]', 'top');



flush_rewrite_rules();

}

add_action('init', 'products_add_rewrite_rules');

Answer 4:

While not your exact desired URL structure, you can get:

/products
» View all custom posts

/products/type/cell-phones
» View all custom posts with the taxonomy cell-phones

/products/type/cell-phones/brand/samsung
» View all custom posts where the taxonomy is cell-phones AND samsung

/brand/samsung
» View all custom posts where the taxonomy is samsung

/product/test-product-1
» View the product (single custom post)

without having to specify custom re-write rules.

It does require that you register your taxonomies and custom post types in a particular order though. The trick is to register any taxonomy where the slug begins with your post-type’s slug before you register that custom post type. For example, assume the following slugs:

product_type taxonomy slug               = products/type
product custom_post_type slug            = product
product custom_post_type archive slug    = products
product_brand taxonomy slug              = brand

Then you could register them in this order:

register_taxonomy( 
    'products_type', 
    'products', 
        array( 
            'label' => 'Product Type', 
            'labels' => $product_type_labels,
            'public' => true, 
            'show_ui' => true, 
            'show_in_nav_menus' => true, 
            'args' => array( 'orderby' => 'term_order' ),
            'rewrite' => array( 'slug' => 'products/type', 'with_front' => false  ),
            'has_archive' => true,
            'query_var' => true, 
        ) 
);

register_post_type('products', array(
    'labels' =>$products_labels,
    'singular_label' => __('Product'),
    'public' => true,
    'show_ui' => true,
    'capability_type' => 'post',
    'hierarchical' => false,
    'rewrite' => array('slug' => 'product', 'with_front' => false ),
    'has_archive' => 'products',
    'supports' => array('title', 'editor', 'thumbnail', 'revisions','comments','excerpt'),
 ));

register_taxonomy( 
    'products_brand', 
    'products', 
        array( 
            'label' => 'Brand', 
            'labels' => $products_brand_labels,
            'public' => true, 
            'show_ui' => true, 
            'show_in_nav_menus' => true, 
            'args' => array( 'orderby' => 'term_order' ),
            'rewrite' => array( 'slug' => 'brand', 'with_front' => false  ),
            'has_archive' => true,
            'query_var' => true, 
        ) 
);

If you absolutely have to have a URL like:

/products/type/cell-phones/brand/samsung/test-product-1
» View the product (single custom post)

Then you would require a rewrite rule something like this:

    add_rewrite_rule(
        '/products/type/*/brand/*/([^/]+)/?',
        'index.php?pagename='product/$matches[1]',
        'top' );

UPDATE
https://stackoverflow.com/questions/3861291/multiple-custom-permalink-structures-in-wordpress

Here’s how you correctly re-define the single post URL.

Set re-write to false for the custom post type. (Leave the archive as is) and then after registering the taxonomies and posts, also register the following rewrite rules.

  'rewrite' => false

   global $wp_rewrite;
   $product_structure = '/%product_type%/%brand%/%product%';
   $wp_rewrite->add_rewrite_tag("%product%", '([^/]+)', "product=");
   $wp_rewrite->add_permastruct('product', $product_structure, false);

Then filter post_type_link to create the desired URL structure – allowing for unset taxonomy values. Amending the code from the linked post, you’d have:

function product_permalink($permalink, $post_id, $leavename){
    $post = get_post($post_id);

    if( 'product' != $post->post_type )
         return $permalink;

    $rewritecode = array(
    '%product_type%',
    '%brand%',
    $leavename? '' : '%postname%',
    $leavename? '' : '%pagename%',
    );

    if('' != $permalink && !in_array($post->post_status, array('draft', 'pending', 'auto-draft'))){

        if (strpos($permalink, '%product_type%') !== FALSE){

            $terms = wp_get_object_terms($post->ID, 'product_type'); 

            if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0]))  
               $product_type = $terms[0]->slug;
            else 
               $product_type = 'unassigned-artist';         
        }

        if (strpos($permalink, '%brand%') !== FALSE){
           $terms = wp_get_object_terms($post->ID, 'brand');  
           if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) 
               $brand = $terms[0]->slug;
           else 
               $brand = 'unassigned-brand';         
        }           

        $rewritereplace = array(
           $product_type,
           $brand,
           $post->post_name,
           $post->post_name,
        );

        $permalink = str_replace($rewritecode, $rewritereplace, $permalink);
    }
    return $permalink;
}

add_filter('post_type_link', 'product_permalink', 10, 3);

Now I just need to figure out how to re-write the brand taxonomy url without the leading brand tag, and I should match your desired URL exactly.

References

Loading...