1

I'm currently starting out with C so I thought I'd try creating my own custom list. Here's the code:

#include <stdio.h>

struct list {
    char data[10];
    struct list *n;
};

void clist(struct list *a) {
    int j=(sizeof(a)/sizeof(a[0]));
    j--;    
    for(int i=0; i<j-1; i++) {
        struct list *next=&a[i+1];
        a[i].n=next; 
    }
}

int main() {

    struct list first = {.data="one", .n=NULL};
    struct list second = {.data="two", .n=NULL};
    struct list third = {.data="three", .n=NULL};

    struct list arr[] = {first, second, third}; 
    struct list *p=&arr[0];

    clist(p);

    struct list looper = first;

    while(looper.n!=NULL) {
        printf("%s ", looper.data);
        looper = *looper.n;
    }

    return 0;
}

So basically I have a struct that saves a char array and a pointer. I initialize them and then I try to link them together by giving it to the clist method. There lies the problem: it seems clist isn't getting anything useful as the variable j stays at 0. If I do the whole size calculation before giving the array to the clist method, I'm getting the correct 3 as a result. Why is that?

Joshua Dannemann
  • 2,003
  • 1
  • 14
  • 34
skulpt
  • 527
  • 2
  • 6
  • 25

2 Answers2

2

In C, array parameters are treated as pointers . So the expression sizeof(a)/sizeof(a[0]) becomes sizeof(int *)/sizeof(int).

So what you are essentially getting is (how big your address is) / (size of integer)

The solution to this would be to send the number of elements in array a as another parameter to the function.

Haris
  • 12,120
  • 6
  • 43
  • 70
  • Agree, but I would change "array parameters are treated as pointers" to "array is memory pointer". – Andrejs Cainikovs Oct 26 '15 at 16:58
  • @AndrejsCainikovs An array is not a pointer. – n. m. could be an AI Oct 26 '15 at 17:00
  • @AndrejsCainikovs Array is not a "memory pointer", but a label for a memory address. – this Oct 26 '15 at 17:01
  • I meant "In C, array variable points to a memory location", to be more precise. But you got the point. – Andrejs Cainikovs Oct 26 '15 at 17:01
  • @AndrejsCainikovs i just wrote that to make the OP understand that when array is passed as parameter, then they start behaving as normal pointers rather then arrays. – Haris Oct 26 '15 at 17:03
  • @AndrejsCainikovs If you are using the definition of pointing which is normally used for pointers, then your statement isn't correct. Be unambiguous. – this Oct 26 '15 at 17:03
  • @this An array is an obhect. An object is a region of memory. It is not a label and it is not an address. Like any object, it has an address, but it isn't one. – n. m. could be an AI Oct 26 '15 at 17:05
  • @AndrejsCainikovs "array variable points to a memory location" no, it doesn't. – n. m. could be an AI Oct 26 '15 at 17:08
  • I don't really get it though. I do the same in another program, but with a char array: (no idea how to format code in a comment window so I'll just post a pastebin link) http://pastebin.com/23B4DBX1 And it does display 8, like it should in this case. Why does it work here, but not with the code in my original post? – skulpt Oct 26 '15 at 17:09
  • @n.m. I wasn't talking about case labels as defined in the Standard. I should have said an array identifier represents a memory address, but in no case does it point there like a pointer does. You are correct that the word label should not be used in conjunction with arrays as it could introduce confusion. – this Oct 26 '15 at 17:11
  • @skulpt, thats because the size of your address is `8`. Change the number of elements, it will still show `8` – Haris Oct 26 '15 at 17:12
  • Well ain't that a stupid coincidence. I would have never guessed that. Thanks a lot. – skulpt Oct 26 '15 at 17:13
  • @skulpt you're welcome. :) – Haris Oct 26 '15 at 17:14
  • There is an established term *array decay* for what's going on. `a` is not "treated as" a pointer, it *is* a pointer. – n. m. could be an AI Oct 26 '15 at 17:16
  • @n.m. "no, it doesn't" Yes, it does. Please elaborate. – Andrejs Cainikovs Oct 26 '15 at 17:17
  • @this "array identifier represents a memory address". Incorrect, it represents an object. An object has an addres, but it isn't an address. – n. m. could be an AI Oct 26 '15 at 17:18
  • @n.m. Please note, we are talking about pure C here, not Java. – Andrejs Cainikovs Oct 26 '15 at 17:19
  • @n.m. I never said an array is an address, it represents one, via the identifier. Your last sentence is just ridiculously obvious. – this Oct 26 '15 at 17:21
  • @this Any object "represents" an address by virtue of having a unique address. Arrays are not special in this regard. – n. m. could be an AI Oct 26 '15 at 17:24
  • @this What identifier? Correct me if I'm wrong, but In C there is no such thing as an array. It's a pseudo-thing that has plain memory operations underneath... – Andrejs Cainikovs Oct 26 '15 at 17:25
  • @n.m. I'm glad we agree. – this Oct 26 '15 at 17:27
  • @AndrejsCainikovs Please open the C standard, scroll down to index, and verify that the word "array" is indeed in it and that it is clearly and precisely defined. – n. m. could be an AI Oct 26 '15 at 17:32
  • 1
    An array identifier used in an expression (sometimes called an "rvalue") evaluates as a pointer to the first element on the array. The exception is when the array identifier is used as an operand of `sizeof` (or in gcc `typeof`), in which case the identifier represents the array object itself. An array type used in a function parameter is changed to a pointer type. – Ian Abbott Oct 26 '15 at 17:34
0

Your code has several errors.

The first one is that inside function clist expression

sizeof(a)/sizeof(a[0])

is equivalent to

sizeof( struct list * ) / sizeof( struct list )

and will be equal to 0 because there are used integer values and the size of the pointer is less than the size of the pointed structure object.

You need expicitly pass the size of the array to the function. But even the variable j will be indeed equal to the size of the array this code in the body of the function is invalid

j--;    
for(int i=0; i<j-1; i++) {
    struct list *next=&a[i+1];
    a[i].n=next; 
}

Let's assume that the array has two elements. In this case initial value of j will be also equal to 2. After statement

j--;    

it will be equal to 1 and inside the loop

for(int i=0; i<j-1; i++) {

condition

i<j-1

will be evaluated to false. So the loop will not be executed and the list will not be built.

Also this loop in main

while(looper.n!=NULL) {
    printf("%s ", looper.data);
    looper = *looper.n;
}

will not display the data member of the last element because the last element has data member n equal to NULL.

I suggest the following modification of your program

#include <stdio.h>

struct list 
{
    char data[10];
    struct list *next;
};

void clist( struct list *a, size_t n ) 
{
    for( size_t i = 0, j = 1; j < n; ++i, j++ )
    {        
        ( a + i )->next = a + j; 
    }
}

int main( void )
{
    struct list first  = { .data="one",   .next = NULL };
    struct list second = { .data="two",   .next = NULL };
    struct list third  = { .data="three", .next = NULL };

    struct list arr[] = { first, second, third }; 

    clist( arr, sizeof( arr ) / sizeof( *arr ) );

    for ( struct list *first = arr; first != NULL;  first = first->next ) 
    {
        printf( "%s ", first->data);
    }


    return 0;
}

Its output is as it is expected

one two three
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335