2

I'm a beginner of C and now I'm learning pointer and dynamic memory allocation. I want to write a simple program to create empty arrays and check for the existence of a given number. Here's my code:

/* create an empty array pointer */
int* createArray(){
    int *a = (int*) malloc(sizeof(int));
    return a;
}

void findArrayElement(int *list, int element){

    int i;
    int len = (sizeof(list) / sizeof(int));
    if (sizeof(list) == 0) {
        printf("NO\n");
        return;
    }
    for (i=0; i<len; i++) {
        if (list[i] == element) {
            printf("YES\n");
            return;
        }
    }

    printf("NO\n");
}

int main(int argc, const char * argv[]) {

    int *p;
    p = createArray();

    printf("size of int is: %lu\n", sizeof(int));
    printf("size of p is: %lu\n", sizeof(p));
    printf("LENGTH of p is: %lu\n", ARRLENGTH(p));

    findArrayElement(p, 2);
    findArrayElement(p, 0);

    return 0;
}

But when I run the program, I always get 'YES' when I looking for 0, so

  1. Is there a way to differentiate integer 0 and a complete empty array?
  2. Also I'm not sure whether my function createArray() is a correct way to create an empty array.

Thanks guys.

Compound07
  • 143
  • 2
  • 8

2 Answers2

5

Is there a way to differentiate integer 0 and a complete empty array?

How do you define an empty array? Once you allocate a memory chunk and assign it to a pointer, it already has some value (which is undefined in case of alloc). The most used way to mark a pointer as not used or not allocated os to assign NULL to it.

Also I'm not sure whether my function createArray() is a correct way to create an empty array.

sizeof returns the number of bytes which the given object (or type) occupies in the memory. In your case sizeof(list) returns 8 as it is a pointer. In oder to allocate an array, the function has to receive its size. Currently it always allocates size for one integer only.

Edit: Adding example.

/* create an empty array pointer */
int* createArray(size_t size)
{
    return (size ? (int*) malloc(sizeof(int)*size) : NULL);
}

So now the returned pointer should be 'coupled' with the size of the array. Which means that each function that receives an array as a parameter should receive also its size.

Alex Lop.
  • 6,810
  • 1
  • 26
  • 45
  • This code is unnecessarily complicated, and has a redundant cast. `return malloc(sizeof(int) * size);` is simpler. `malloc` is well defined in the case of allocating zero bytes. – M.M Aug 30 '15 at 04:35
  • I really tried that before, but I'm not sure about `malloc` with size 0. Is that mean when I pass 0 to the function, I could get a pointer to an empty array? – Compound07 Aug 30 '15 at 04:39
  • @MattMcNabb `malloc` returns `void*` and I like to make code clear and consistent, also `malloc` of 0 is not well defined and not necessarily returns NULL. http://stackoverflow.com/questions/1073157/zero-size-malloc . – Alex Lop. Aug 30 '15 at 05:24
  • @SensEyeNULL according to my example you will get NULL if you pass 0 as array size. Which means that nothing was allocated. – Alex Lop. Aug 30 '15 at 05:27
  • sorry, I meant "not undefined" : you may either get null or non-null pointer but whichever of those happens, it is fine and does not break the rest of the program. Yes malloc returns `void *`, not sure what your point is there. Why didn't you write `(int *)NULL` then? – M.M Aug 30 '15 at 05:30
  • @MattMcNabb casting doesn't cost any additional memory usage or performance impact. It is a matter of coding style. – Alex Lop. Aug 30 '15 at 05:43
  • @AlexLop. Yes, I am trying to say that using redundant casts is poor style. In general they make code harder to read and may cause the compiler to suppress warning or error messages. – M.M Aug 30 '15 at 05:52
0

sizeof returns the memory size of the array pointer, regardless of contents.

edit: if it exists in memory, it will be nonzero.

edit 3: removed inaccurate information, see the comments about creating a variable to record the length. Also from comments, note that your createArray function is creating an array for exactly 1 integer. In C, arrays are of fixed length. So this Array will always be the same size (whether you stored something in it or not). sizeof(pointer) will always return the memory allocated for the pointer, not the memory allocated for the array at which it is pointing.

jwkicklighter
  • 126
  • 1
  • 9
  • Do you think that `sizeof(list)` or `sizeof(p)` return the size of an array in the posted code? How would you determine if an array is "empty" by checking all indices? – Blastfurnace Aug 30 '15 at 03:52
  • Even if I declare an empty pointer by `int *p`, the `sizeof(p)` will give me 8, so I think `sizeof` is not the correct way of doing this, but I can't think of another solution. – Compound07 Aug 30 '15 at 03:57
  • Because the pointer itself is memory, so `sizeof()` is giving you the size of ram used to store that "empty" pointer. – jwkicklighter Aug 30 '15 at 03:59
  • @SensEyeNULL C does not track the size of arrays for you. You have to do that. `list` is a pointer, so `sizeof(list)` returns the size of a pointer. – user253751 Aug 30 '15 at 04:00
  • 1
    @jwkicklighter: Testing for equality with NULL (assuming that's what you meant by _null_) will only tell you if that `int` is equal to `0`. That's a perfectly valid value for an `int`. Do you know `C`? – Blastfurnace Aug 30 '15 at 04:02
  • Oh, and I just realized `createArray` is creating a pointer to an array with memory for only 1 integer. – jwkicklighter Aug 30 '15 at 04:03
  • @Blastfurnace I do know C, and an int of 0 is absolutely not "equal to" NULL. Do you know C? – jwkicklighter Aug 30 '15 at 04:04
  • @jwkicklighter: Are confusing this with C# or Java. There is no such thing as an empty `int` in C. – Blastfurnace Aug 30 '15 at 04:06
  • Ah, I think the confusion is because I'm used to making arrays of integer pointers, which can very well be NULL. Rather than arrays of actual integers. – jwkicklighter Aug 30 '15 at 04:09
  • @jwkicklighter: That's correct and there is no way in the language to tell if it's uninitialized or not. It will have a value, perhaps unspecified but it certainly isn't guaranteed to be NULL. – Blastfurnace Aug 30 '15 at 04:09
  • 1
    @immibis So I think I should create a struct with the array and another integer to record the length – Compound07 Aug 30 '15 at 04:10
  • @SensEyeNULL: You don't need a `struct` but you do need to keep track of the array length and pass it, along with the pointer, to functions that need that information. – Blastfurnace Aug 30 '15 at 04:11
  • @jwkicklighter The purpose of `createArray()` is just to create an empty array pointer, if I need to add more elements into the array, I can use `realloc` to give more memory space to the array. So is `createArray()` the correct way if doing so? – Compound07 Aug 30 '15 at 04:14
  • I think @blastfurnace will be of more help here – jwkicklighter Aug 30 '15 at 04:18
  • @jwkicklighter I don't know whether you really mean it or just joking, but I do really appreciate everyone's help :) – Compound07 Aug 30 '15 at 04:23
  • @Blastfurnace What if I have a lot of arrays, I don't think it's the best way to have dozens of integers to keep track of the length of each array... – Compound07 Aug 30 '15 at 04:27
  • @SensEyeNULL I'm on mobile and apparently haven't touched C recently enough to give helpful answers without testing, so I really mean it. Hopefully I got something helpful across! – jwkicklighter Aug 30 '15 at 04:28
  • 1
    @SensEyeNULL: How about an array of array lengths? But seriously, that is a design question and it's good you're thinking about it. A `struct` that keeps an array pointer together with its length is one solution. – Blastfurnace Aug 30 '15 at 04:29
  • @jwkicklighter Thanks! Every idea is helpful to a beginner! – Compound07 Aug 30 '15 at 04:31
  • @Blastfurnace Thanks! I'll try that. – Compound07 Aug 30 '15 at 04:33