deceptikon 1,790 Code Sniper Team Colleague Featured Poster

My question is when does this function works improperly and why?

Technically it works improperly when you call it with an input stream or an update stream in input mode. That is, if you use fopen() with a "w" mode, or a "+" mode and you're currently in the process of reading from the stream, or stdin.

In practice, all of the above situations are okie dokie iff the compiler supports them (and some do, including Borland and Microsoft compilers). In terms of best practice, fflush() on an input stream is frowned upon.

However, note that calling fflush() on an output stream is both well defined and recommended for things such as forcing a user prompt to display, well...promptly. :)

Nowadays I use scanf("[^\n]") to flush input stream. Is this ok?

Close. The correct call for scanf() to read up to a newline would be:

scanf("%*[^\n]");

This isn't complete though, because the newline will still be in the stream. You still need to extract it. One way would be to add an ignored character match in the format string:

scanf("%*[^\n]%*c");

This might not be as flexible though, if you want to do other stuff like count discarded characters. Another way would be to call getchar() after scanf():

scanf("%*[^\n]");
getchar();

Finally, there's the far more common (and faster!) method of calling getchar() in a loop. I'll even give you a function that you can call instead of having to write it …

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I'm more than happy to explain anything about my posts, so please don't be afraid to ask for clarification. If you stay quiet, I'll just assume that you understood and expect you to apply that understanding in future posts.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Try opening windows.h and reading the declarations. Then for each declaration, do a search on MSDN.

And here's a tip: MSDN's search facility is an embarrassment of epic proportions, so if you need to do anything but an exact match search, use Google with the site: filter.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

It's not as simple as that, but if you're only using getline() then there should be no need to ignore garbage if you're using getline() correctly. The problem of garbage nearly always stems from reading partial lines or mixing getline with formatted input (in the form of the >> operator).

The latter is explained in painful detail here.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

So I request you "DON'T GUESS FROM THE COMPILER THAT WHICH NATIONALITY A PERSON HAS".

It looks to me like he guessed India from the OP's name, and then further speculated the compiler based on previous observations (an observation I've made as well). I don't think you should feel insulted, but I'll ask two questions that may calm your anger:

  1. Is Shankar an uncommon name in India or exceptionally common in another country that you would be insulted if it were associated with India?

  2. Is Turbo C not the most commonly used compiler in educational institutions by far in India?

If you answered yes to either of those then you can take offense and address the issue privately with DeanMSands3. Otherwise, I'd suggest growing some thicker skin and not taking offense at the first potentially negative mention of your country. That's how pointless wars are started.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I suspect it would be knowledge of Microsoft software like Visual Studio or the Office suite. By the way, that question is unrelated to this thread, and C in general. You would be better off starting a new thread in an appropriate forum.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

It's unspecified behavior if you access a member of a union that's different from the last one used to store a value. Though one of three cases can be expected:

  1. The correct value will be printed.
  2. A garbage value will be printed.
  3. The program will blow up from a trap representation.

In the case of #1, the bytes stored in the union's memory are a valid and consistent representation of the type of the member being accessed. So in the code you posted, I would expect output of 20.

In the case of #2, there's no meaningful representation of the bytes, so you'll get a garbage value. This would be the case for storing an integer value and then trying to access it through a floating-point member:

#include <stdio.h>

int main(void)
{
    union foo { int a; double b; } foo;

    foo.a = 123;
    printf("%f\n", foo.b);

    return 0;
}

Finally, if the value when represented by the type of the accessed member is a trap representation for that type, you're screwed.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

If you don't bother to read my replies then I'm going to stop trying to help you. How do I know you aren't reading my replies? Because if you were, then you'd realise that I already answered this one with another post on a similar topic.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

The program still runs without errors. Did I do that right?

Nope, you forgot to read the warnings. Just because the code compiles and runs doesn't mean it compiled cleanly and is correct.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Are you sure you're not a bad programmer? Because your logic is atrocious. ;)

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

No, but this is the case for bit field having width zero.

A zero width unnamed bitfield aligns the next bitfield to the listed type boundary rather than a programmer-specified number of bits. A non-zero width unnamed bitfield aligns the next bitfield to a programmer-specified number of bits:

/* Assuming unsigned int is 32-bits */
struct Foo {
    unsigned a: 5;
    unsigned b: 2; /* Take up 7 bits starting at the 1st bit */
    /*
        Force the next bitfield to start at the next 32-bit entity.
        This means we're skipping the remaining 25 bits of the current
        32-bit entity.
    */
    unsigned  : 0;
    unsigned c: 7; /* Take up 7 bits starting at the 1st bit */
};

/* Assuming unsigned int is 32-bits */
struct Foo {
    unsigned a: 5;
    unsigned b: 2; /* Take up 7 bits starting at the 1st bit */
    /*
        Skip the next 7 bits of the current 32-bit entity.
    */
    unsigned  : 7;
    unsigned c: 7; /* Take up 7 bits starting at the 15th bit*/
};
I_m_rude commented: ohh! really awesome! +2
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Your corrections are irrelevant because the problem is the same as in my speculation about how the code really looked. b and c aren't parameters to the macro, they're expected to be declared and initialized as named variables:

#include <stdio.h>

#define loop() for (; b < c; b++)

int main(void)
{
    int i = 0;
    int b = 0, c = 15;

    loop(i, 15)
    {
        printf("%d\n", i);
    }

    return 0;
}

The argument list is actually wrong, and you should at least get a warning about having too many arguments in a parameter list expecting none. As you already know, the correction is to add those parameters to the macro:

#include <stdio.h>

#define loop(b, c) for (; b < c; b++)

int main(void)
{
    int i = 0;

    loop(i, 15)
    {
        printf("%d\n", i);
    }

    return 0;
}

What you can't do is remove the empty parameter list, like this:

#define loop for (; b < c; b++)

The reason is because when you say loop(i, 15), what actually happens is for (; b < c; b++)(i, 15), and that's a syntax error unless the next token is a semicolon to turn (i, 15) into a do nothing statement.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Any other link can you provide for making my concepts more and mpre clear.

This one is mostly about data structures and algorithms, but there's also a reasonably good article on pointers which includes mention of how they relate to arrays.

I don't doubt I could come up with more links, but my memory works more along the lines of hearing a specific question or comment and thinking "oh, I read an article about that" as opposed to just randomly thinking of something cool or useful.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I think all of your problems stem from re-opening the file in your functions. Opening a file stream in write mode will truncate the file to zero length, so every time you call print(), the data in the file gets wiped out.

One way to fix it without significant changes is open the file in main() just before your second loop, remove the call to open() in print(), and finally remove the call to close() in display():

#include <iostream>
#include <cstdlib> 
#include <fstream>
#include <vector>
using namespace std;

int array[7][4];

fstream file2;

template< typename T > void display( const vector< vector<T> >& matrix )
{
    for(int i = 0; i < 7; ++i)
    {
        for(int j = 0; j < 4; ++j)
        {
            array[i][j] = matrix[i][j];
            file2 << array[i][j] << " ";
        }
        file2 << "\n";
    }    
    file2 << "\n";
}

template< typename T >
vector< vector<T> > get( const vector< vector<T> >& m, size_t n, size_t i, size_t j )
{
    const size_t N = m.size() ;
    vector< vector<T> > slice(n) ;

    for( size_t k = 0 ; k < n ; ++k )
        for( size_t l = 0 ; l < n ; ++l )
            slice[k].push_back( m.at(k+i).at(l+j) ) ;

    return slice ;
}

template< typename T > void print( const vector< vector<T> >& m )
{
    for( size_t i = 0 ; i < m.size() ; ++i )
    {
        for( size_t j = 0 ; j < m[i].size() ; ++j )
        {
            file2 << m[i][j] << " …
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

This may help. It's written by Chris Torek, who's a man deserving of great respect due to his deep knowledge of C.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I don't particularly like how you're trying to lump everything together because it complicates an already complicated algorithm. There are three separate parts to replacing a substring:

  1. Find a matching substring.
  2. Make room for the replacement.
  3. Insert the replacement.

Separating the tasks conceptually will help you write code that can easily be modularized into functions. Also note that making room for the replacement isn't as simple as it first seems because you need to consider differing sizes of the matched and replacement substring:

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

int main(void)
{
    char line[BUFSIZ] = "thisisatest";
    char match[BUFSIZ] = "isa";
    char replace[BUFSIZ] = "BOOGA";
    int i, j, k;

    /* Step 1: Find a matching substring (without the standard library) */
    for (i = 0; line[i]; ++i) {
        for (j = i, k = 0; line[j] && match[k]; ++j, ++k) {
            if (line[j] != match[k])
                break;
        }

        if (match[k] == '\0')
            break;
    }

    /* Step 2: Make room for the replacement (without the standard library) */
    if (line[i]) {
        int old_end = i + strlen(match);
        int new_end = i + strlen(replace);

        if (old_end > new_end) {
            /* Make a smaller hole */
            while ((line[new_end++] = line[old_end++]) != '\0')
                ;
        }
        else if (old_end < new_end) {
            /* Make a bigger hole (don't forget to shift the null character too) */
            int j = strlen(line);
            int k = strlen(line) + (new_end - old_end);
            int n = j - old_end + 1;

            while (n--)
                line[k--] = line[j--];
        }
    }

    /* Step 3: Insert …
I_m_rude commented: great +0
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I would say that, particularly in portable code, the C bitfield syntax is of no use.

Only if you're using it to map an object or performing I/O with it. Bitfields are especially useful for flags, and in that case they're generally simpler to work with "out of the box" than bit twiddling. You can write macros to simplify the bit twiddling, but that's extra effort that may not be necessary.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

You'll probably be able to relate to this

That's hilarious, unfortunately because it's so true. For example, programming books have an annoying tendency to leave the hardest and most important parts as "exercises for the reader".

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

For future reference, both a newline and a space in the format string are unnecessary. Any single whitespace character will tell scanf() to read any and all subsequent whitespace from the stream, so technically you could do this:

scanf(" %c", &b);

And it'll catch any number of spaces, tabs, and newlines. It'll also royally jack up your I/O logic if you're not expecting that behavior. ;)

Also note that the only specifiers that don't read leading whitespace by default are %c, %[, and %n. All of the other specifiers do the "right" thing.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I'm willing to bet that you didn't think the Enter key counts as a character in the stream. Your second scanf() reads the newline from pressing the Enter key, so you're replacing whatever is typed for b with '\n'. Unless you type multiple characters for b, of course.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

scanf()'s %s specifier doesn't read whitespace, that's the delimiter. Since you learned not to use gets(), the proper replacement is fgets(), not scanf().

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

For the most part. For everything else there's google.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Doesn't compiler give the error if array limits are crossed ?

It's undefined behavior, anything could happen.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

@deceptikon sir, So that means there isn't any solution for this problem as you said it must roll back fully ?

No offense, being fully aware that leading with "no offense" means something offensive will follow, but I find this back and forth of saying the same damn thing with slightly different words tiresome. I said something very clearly and with no ambiguity (ie. "you really have no choice but to roll back up the recursive chain"). You repeated it equally clearly and with full understanding (ie. "there isn't any solution for this problem as you said it must roll back fully"). Why should I repeat myself when it's obvious that you understood?

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

There are many libraries you can (and should!) use. Cryptography is exceptionally easy to get wrong, where the result appears to work but is easily cracked. OpenSSL is one popular library.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Yes, I double checked and it's definitely undefined behavior to modify a const-qualified object.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

If you're not using Turbo C, you can't use graphics.h. If you're new to game programming I'd recommend writing a few text-based games first, then look for a more modern graphics library. SDL and Allegro are two names that pop up regularly for starting out.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

how to solve

Start by trying something on your own or asking a specific question. We're not here as a free homework writing service.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Barring truly hideous solutions like setjmp and longjmp, or terminating the program entirely with exit() or abort(), you really have no choice but to roll back up the recursive chain. This is one of the down sides of recursion, especially when dealing with things like ad hoc traversal over a binary search tree.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

The Windows API defines a macro called ERROR, which is replacing your use of ERROR with whatever value is defined. It does the same thing with TRUE and FALSE, which is why in the past I was forced to do annoying things like this:

enum boolean { B_FALSE, B_TRUE };

This is precisely the type of problem that namespaces were meant to solve. Sadly, the preprocessor is its own beast, and a beast it can be. ;)

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I haven't get what you trying to say.

I really can't simplify it any further.

why is this thread started ?

Because I'm better at writing snippets than coming up with ideas for snippets that people would like to see and learn from. I suspect I'm not alone in that.

I_m_rude commented: confidence! +0
<M/> commented: :) +8
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

If the pragma (excluding a few standard pragmas starting with C99) is supported by your compiler, it must be documented and it must work as documented. But that same pragma need not be supported by a different compiler.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

why one should not use XoR or arithmetic operation to swap number???

Because it's inferior to using a temporary variable, and the original reason for avoiding a temporary variable is totally irrelevant unless you're on a severely memory constrained platform. And by "severely", I mean so much that you actually map out your register usage and design algorithms to avoid stack or heap use. Oh, and this also assumes that you're writing your code directly in assembly because C is just too heavy.

Then how to swap numbers without using temparory variable.

http://en.wikipedia.org/wiki/XOR_swap_algorithm

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

And before anyone chimes in with swaps using XOR or arithmetic operators that they think are clever: your solution is bad, and you should feel bad.

WaltP commented: Nice. And correct! +14
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Pragmas are implementation-defined (barring a few standard ones starting with C99). Read your compiler's documentation for supported pragmas and what they do.

However, I'll give you an example of a somewhat common pragma: pragma once.

I_m_rude commented: link is damn good! +2
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Let's break it down completely into separate statements:

/*
    *p++ = c;
*/
int *temp = p;
*temp = c;
p = p + 1;

Throughout the entire expression, the value of p before the increment is used. Then after the expression reaches a sequence point (the semicolon in this case), the "temporary" variable is destroyed and p evaluates to the incremented value.

The operators are applied in a somewhat unintuitive way. First the ++ binds to p, so you're incrementing the address stored in p. Next, the * binds to the unincremented address due to how the postfix increment operator works. Finally, the assignment operator is applied on the result of the dereference, so c is assigned to the pointed to object.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

int u[]={}

You need to give your array a size. I'm surprised there wasn't an error from this definition.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Can you please tell what is difference between "null pointer", "NULL macro", null string, null character and null pointer constant ?

I'm starting to wonder if you're actually a beginner to C or just seeding the forum with questions. ;)

Anyway, a null pointer is the concept of a pointer that points to nothing in particular, but can be predictably tested. That's as opposed to an uninitialized pointer, which could potentially point to anything and thus can't reliably be checked for validity.

A null pointer constant is the concrete form of an initialization value for a null pointer. It's essentially any integer value that equates to 0, either cast or implicitly converted to pointer context.

The NULL macro is a symbolic constant representing a null pointer constant. In C you'll typically see one of these two definitions:

#define NULL ((void*)0)

or

#define NULL 0

In C++ the former is problematic in light of more stringent type system, so NULL is defined simply as 0. But because C allows an implicit conversion from void* to any other pointer type (except a function pointer), NULL can safely include a cast to void*. However, because many C compilers are also C++ compilers, defining NULL as 0 instead of ((void*)0) appears to more common.

Moving away from pointer context, the null character (sometimes referred to as NUL, though there's no standard macro for it) is a character with the value 0. The escape character is '\0', though you …

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Would "\n" be stored inside the same address so that it still functions as a new line or not since I'm using this as a .cgi file connected to an html file and only <br> works? Because I have to save "copy" in a text file.

If it's going into a text file then '\n' will act as a newline. If it's being rendered by a browser, I'm not 100% sure whether the CGI interpreter will convert that to an HTML line break or not. That's something you'd need to test and adjust accordingly. I actually haven't worked with CGI in about 10 years, so the details are fuzzy. ;)

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

char *copy = NULL,addressholder2;
copy = &addressholder2;
*copy = *string; //string is the result of the html form
copy[1] = '\0';
strcat(copy,"test"); //HERE IS THE CODE THAT WORKS

This is terrifying. So you have a pointer to a single character, and then immediately start writing beyond that single character as if it were an array to infinite memory. This code exhibits a profound misunderstanding of how pointers and memory work in C.

Assuming that you haven't done something equally wrong with string, it looks like you can use the length of string as a size for copy because it's pretty much guaranteed to be more than enough:

char *copy = malloc(strlen(string) + 1);

if (copy) {
    /* This may be overly paranoid, but handle an empty string */
    if (string[0] != '\0') {
        copy[0] = string[0];
        copy[1] = '\0';
    }
    else {
        copy[0] = '\0';
    }

    /* Now do all of your stuff */
    strcat(copy, "test");

    ...
}

Also, don't forget to release the memory for copy by calling free() at a suitable location (ie. when you're done using the memory).

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

This is a declaration:

int add(int a, int b);

It specifies that add is a function returning an integer that takes two integer parameters. This is the function signature which tells the compiler the "attributes" and "interpretation" of the symbol add.

This is a definition:

int add(int a, int b)
{
    return a + b;
}

Because a body is provided, the declaration becomes a definition, but it still also functions as a declaration.

Here's a summary of object declarations and definitions at either block or file scope:

int a;        /* This is a (tentative) definition */
int b = 0;    /* This is a definition */
extern int c; /* This is a declaration */

int main(void)
{
    int d;        /* This is a definition */
    int e = 0;    /* This is a definition */
    extern int f; /* This is a declaration */

    return 0;
}

Given your eye for detail I'll recommend that you don't concern yourself with tentative definitions for now (because I'm sure you'd ask about it otherwise), just follow the more sensible concept from C++ that it's a definition unless you specifically make it a declaration with the extern keyword.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Yes, you can do that. But the use of ull in the structure definition needs to specify a pointer:

typedef struct node ull;
struct node
{
      int a;
      ull *p;
}hello;

secondly, what is the difference between declaring a structure and defining a structure.

From the C standard:

A declaration specifies the interpretation and attributes of a set of identifiers. A definition of an identifier is a declaration for that identifier that:

  • for an object, causes storage to be reserved for that object;
  • for a function, includes the function body;
  • for an enumeration constant or typedef name, is the (only) declaration of the identifier.

So according to the C standard, this is a declaration:

struct node;

But so is this:

struct node {
    int data;
    struct node *next;
};

However, this is a definition of head and a declaration of the struct in one statement:

struct node {
    int data;
    struct node *next;
} head;

I prefer the C++ terminology that has struct node; as a declaration but listing out the members specifies a definition of the structure. That's simpler, in my opinion, and more consistent, than having both as declarations.

I_m_rude commented: nice one! +0
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

You have a pointer, not an array. So you need to point that pointer to an array or dynamically allocate some memory to it before using it. Then, you need only remember to dereference the pointer before indexing it:

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

void display(int (*p)[10])
{
    for (int i = 0; i < sizeof *p / sizeof **p; i++)
        printf("%-2d", (*p)[i]);
}

int main(void)
{
    int data[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    int (*p1)[10] = &data;              /* Use an existing array */
    int (*p2)[10] = malloc(sizeof *p2); /* Dynamically allocate */

    /* Initialize the dynamic array */
    for (int i = 0; i < sizeof *p2 / sizeof **p2; i++)
        (*p2)[i] = i + 1;

    /* And use the pointers */
    display(p1);
    putchar('\n');
    display(p2);

    return 0;
}
I_m_rude commented: Excellent!! +2
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

Codepad is wrong, probably because it doesn't use appropriate flags for strict compilation as C. AT the very least there should be a warning.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

What happens if I removed the "using" word? Will it affect my program?

It would fail to compile...

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

but deceptikon said that typecast is neccassary in this case, otherwise nature will be undefined.

I said that the typecast is safe, but use of the resulting pointer could potentially be undefined. However, phani1092 is incorrect in saying that the cast isn't necessary because you have to either conform to C's type system or subvert it. If you want to assign a naked 2D array to a pointer to int (as in the original example), you must subvert the type system with a cast. If you want to conform to the type system, you must use the correct destination type:

int arr[2][2][2] = {1, 2, 3, 4, 5, 6, 7, 8};
int (*q)[2][2] = arr;
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

my question is that how can we use "main" (only name without parenthesis) as the pointer to a function ? because
main() is a function. I am not getting it how is it true ?

It's syntactic convenience based on the fact that you can only do two things with a function: call it or take its address. If you're not calling a function with the () operator then you must be taking its address, and thus the address-of operator isn't necessary.

So fun(main) is equivalent to fun(&main).

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

But why does C consider *y++ to be an incremention to the adress of y?

That's just how the precedence rules work.

Is there a reasonable answer to this wierd operator precedence order?

I'm not aware of any rationale for it, though Dennis Ritchie wrote a history of C that might mention it. However, by my recollection the only mention of precedence in that history has to do with bitwise operators.

And will (*y)++ work as expected?

Yes.

@deceptikon what will u say to this statement ?

int *p,x=3;
int c=9;
p=&x;
*p++ = c;
how values are assigned/incremented in the last line ? I think i will get your point after this answer.

You're essentially overwriting x with 9, then incrementing p. Note that this increment is unsafe because pointer arithmetic is only meaningful inside an array or dynamically allocated block.

deceptikon 1,790 Code Sniper Team Colleague Featured Poster

I didn't get one point that how can typecasting an pointer to an array of pinters into an integer pointer make it to point to the forst element in the array ?

You know that array indexing is essentially an offset from the base address of the array, right? So a[5] is equivalent to converting a to a pointer to the first element, then incrementing the pointer by 5 and dereferencing the result (ie. *(a + 5)). Well, all arrays work like that, and the base address is always the first element of the most nested dimension.

So regardless of how you interpret the address, it's always the same address. For example:

#include <stdio.h>

int main(void)
{
    int a[2][3][4];

    printf("%p\n", (void*)a);
    printf("%p\n", (void*)a[0]);
    printf("%p\n", (void*)a[0][0]);
    printf("%p\n", (void*)&a[0][0][0]);

    return 0;
}
deceptikon 1,790 Code Sniper Team Colleague Featured Poster

In the first, the global array is likely to be stored in the BSS (uninitialized data) segment of the executable file itself while the local array is more likely to be drawn from the stack at runtime. Because stack space is already allocated to the executable in one way or another, local variables don't contribute extra bytes to the size of the file.