int main()
{
     printf("%u %s",&"hello",&"hello");
     return 0;
}

can you please explain that how "hello" is working here ? i know it is string constant ? so it is acting as a pointer to a char like i do

char *s= "daniweb"; 

so, if it is the case, then why do i need & to find it's address ? I am little bit confused. Can you explain the output if i don't write & with both "hello" ? thanks in advance.

Edited 3 Years Ago by nitin1

printf("%u %s",&"hello",&"hello");

You don't need the & symbol because character arrays are ALWAYS passed by addfess. When you use the & in the above it will pass the address of the address, which is not what you want.

printf("%p %s","hello","hello");

Also note that %p prints the address of the string

Edited 3 Years Ago by Ancient Dragon

can you please explain that how "hello" is working here ?

Luck. :) Technically it's undefined behavior because you're passing an object of the wrong type to printf(). Functionally though, "hello", &"hello", and &("hello"[0]) all evaluate to the same address, so it's not difficult to see why your output is correct.

so, if it is the case, then why do i need & to find it's address ?

You don't, and in fact the code you posted is wrong because of the & operator. The unadorned string literal has the correct type for %s (I'll address %p in a moment). As AD alluded, %u is incorrect for printing addresses because there's no guarantee that unsigned int can represent the value. The %p specifier exists for formatting addresses, but it's often used incorrectly (see below).

printf("%p %s","hello","hello");

Close. The %p specifier requires a pointer to void, but as a variable argument, the pointer you pass isn't automagically converted to void* for you. Internally, printf() will interpret the object you pass as if it were void*, which can blow up in your face on the off chance that the underlying representation of the two pointer types are different. In practice it's not a problem in all implementations I'm familiar with, but technically it's undefined without a cast. This is the correct call to printf():

printf("%p %s\n", (void*)"hello", "hello");

yoo! very nice explaination sir. take a bow. but sir, i think &"hello" in the first case can be correct ? because i can do this :

printf("%p %s\n", (void*)&"hello", "hello");

isn't this okay ?

that's okay if it is unneccassry. here point is not about if it is useful or not, but is it perfect ? I mean is there any error or undefined bahviour in this ? because i will getthis question to tell "do you find any ERROR in this ? ". thanks alot sir.

here point is not about if it is useful or not, but is it perfect ?

By definition unnecessary stuff makes it imperfect.

I mean is there any error or undefined bahviour in this ?

No, it's legal and will produce the desired behavior portably.

yoo sir! thanks alot. here i wana ask 1 more problem is that if you have 2-D matrix and you want to write a general method for displaying them, then how can i make it ? and i want to pass the 2-D matrix in the function.

display(int a[][],int m,int n);

so m,n is the dimensions and i wondering that i have to pass one dimesnsion in the a[][], and i do that then it will not be genral. so how can i do that ? thanks. i tried some ways , but was not able to do that. thanks.

You're pretty much SOL for built-in array types because all dimensions except the first require a size. In C99 and C11 with VLAs defined you can pass an VLA, but for the most part the recommended solution is a dynamically allocated 2D matrix so that you can pass a pointer to a pointer:

void display(int **a, int m, int n);

ohh... but that is when i will dynamically allocate that. sir, how are arrays stored in memory ? row-majored or column majored ? can i do with the help of this thing ? thanks.

how are arrays stored in memory ?

The compiler can do whatever it wants as long as the resulting behavior is unchanged. That's why it's undefined behavior to treat a 2D array as if it were a 1D array.

then why we study about row major and column order ? then how are we able calculate the adress of a[3][4] given the address of a[0][0] ?

One way to do it is to first allocate the number of rows you want, then for each row allocate the columns. As you can see the memory for the array is not contiguous.

int rows = 5;
int cols = 10;
int **array = malloc(rows, sizeof(int));
for(int i = 0; i < rows; i++)
   array[i] = malloc(cols, sizeof(int));

display(array,rows,cols);

how are we able calculate the adress of a[3][4] given the address of a[0][0] ? how are we able calculate the adress of a[3][4] given the address of a[0][0] ?

That's not possible with my code above

Edited 3 Years Ago by Ancient Dragon

then why we study about row major and column order ?

Because matrix theory is important?

then how are we able calculate the adress of a[3][4] given the address of a[0][0] ?

You let the compiler do it: &a[3][4]. If you want to play address games and do everything manually, you need to allocate your own memory to ensure that it's set up the way you want.

ohh.. that means getting a[3][4], by giving a[0][0] is just theortical and it is not true for compiler to get address like this ? am i right ?

The compiler can do it, but you're not guaranteed anything by the C standard to do it yourself. At least not with built-in arrays.

sir, but if question is like this :

i have little confusion: if a[3][3] is defined and you are given a[0][2] address(32114) and you are asked address of a[1][0] , isn't it 32118 (on 32-bit compiler) ? if not, then what should i answer to this question ? thanks in advance sir.

if a[3][3] is defined and you are given a[0][2] address(32114) and you are asked address of a[1][0] , isn't it 32118 (on 32-bit compiler) ?

Is it probable? Yes. Is it guaranteed? No.

if not, then what should i answer to this question ?

The same answer I've given you several times: there's no guarantee that you can acquire the address of an item in one array from an item in another array, even if those arrays are subdimensions of a 2D array.

There are three solutions:

  1. Recognize that the requirement exhibits a broken design and fix the design.
  2. Replace the 2D array with a manually allocated block of memory that's guaranteed to be contiguous:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define N 3
    #define M 3
    
    int main(void)
    {
        int *base = malloc(N * M * sizeof *base);
    
        if (base) {
            int **matrix = malloc(N * sizeof *matrix);
            int *p;
            int i;
    
            if (!matrix) {
                free(base);
                return EXIT_FAILURE;
            }
    
            for (i = 0; i < N * M; i++) {
                base[i] = i;
            }
    
            for (i = 0; i < N; i++) {
                matrix[i] = &base[i * M];
            }
    
            printf("[0][2] -- %p: %d\n", (void*)&matrix[0][2], matrix[0][2]);
            printf("[1][0] -- %p: %d\n", (void*)&matrix[1][0], matrix[1][0]);
    
            p = &matrix[0][2];
    
            printf("%p: %d\n", (void*)p, *p);
            ++p;
            printf("%p: %d\n", (void*)p, *p);
    
            free(matrix);
            free(base);
        }
    
        return 0;
    }
    
  3. Simply increment your pointer and hope for the best. It'll probably work, but such things tend not to work at the most inopportune times.

sir, malloc guarntess that memory allocated is contigous right ? that's why this code will solve my problem ? if contigous memory is not there, then it will return NULL which you have checked also.
correct me please. thanks.

According to the C standard (§6.5.2.1 (C99)) Arrays in C (and C++ by extension) are always row-major
order: A[row][col]. And, at least as far as I can tell, are also always contiguous in memory: one row followed by the other. Anything else would be irrational. This has the rather convenient advantage of allowing the pointer to a single row to be passed to a function as &A[row][0]. It also guarantees that in-place type conversions (eg, byte arrays to ushort) using type casts will always work.

And, at least as far as I can tell, are also always contiguous in memory: one row followed by the other.

Nope, not guaranteed. The as-if rule is in effect. Provided the result of defined operations is as-if some assumption were true, the implementation need not actually conform to the assumption under the hood.

Anything else would be irrational.

What's irrational is your quoting of the standard on one hand and then appealing to rationality on the other. The standard is always right, even when it's not internally consistent.

This has the rather convenient advantage of allowing the pointer to a single row to be passed to a function as &A[row][0].

I don't see how that advantage benefits from contiguous storage of the first dimension. However, if you're somehow implying that one can do any variation of this:

#include <stdio.h>

void foo(int *p)
{
    while (*p)
    {
        printf("%d\n", *p++);
    }
}

int main(void)
{
    int a[2][4] =
    {
        {1, 2, 3, 4},
        {5, 6, 7, 0}
    };

    foo(&a[0][0]);

    return 0;
}

Then I'd direct you to §6.5.6.8 (C99), the last sentence of which is ambiguous enough to justify a padding element between "contiguous" arrays in memory: "If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated." Technically the arrays may be contiguous, but the presence of such a padding element is a confounding variable in exploiting the contiguous nature.

Further, from Annex J.2 (Undefined Behavior) you have the kiss of death for anyone trying to exploit contiguous arrays in a multidimensional array:

  1. "Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that does not point into, or just beyond, the same array object (6.5.6)."

  2. "Addition or subtraction of a pointer into, or just beyond, an array object and an integer type produces a result that points just beyond the array object and is used as the operand of a unary * operator that is evaluated (6.5.6)."

  3. "An array subscript is out of range, even if an object is apparently accessible with the given subscript (as in the lvalue expression a[1][7] given the declaration int a[4][5]) (6.5.6)."

It also guarantees that in-place type conversions (eg, byte arrays to ushort) using type casts will always work.

Well, the cast will always work. What you do with the result could fail miserably if, for example, the resulting value is a trap representation.

This article has been dead for over six months. Start a new discussion instead.