0

I am trying to create a simple array-expanding function, which creates a new array with the same values as the previous array expanded by a value:

char* test(char array[], int expandBy) {
    char newArray[sizeof(array) + expandBy];
    strncpy(newArray, array, sizeof(array));

    return newArray;
}

However, I am getting the compile-time error expression must have a constant value. All of the answers that I have seen to similar questions suggest using a macro, but I can't use a macro if I don't know the value beforehand.

Does anyone know how I can fix this, or if there is an alternative to this?

ack
  • 1,181
  • 1
  • 17
  • 36
  • 2
    You have a much worse problem than the compiler error: You return a pointer to a local variable. Local variables go out of scope once function returns, and that will leave you with a stray pointer to an array that no longer exist. Attempting to dereference the returned pointer will lead to [*undefined behavior*](https://en.wikipedia.org/wiki/Undefined_behavior). – Some programmer dude Nov 11 '17 at 02:38
  • 1
    On another unrelated note, there is a case in which the [`strncpy`](http://en.cppreference.com/w/c/string/byte/strncpy) will not add the terminator. Look out for that. – Some programmer dude Nov 11 '17 at 02:40
  • Once you pass an array to a function it decays to a pointer. At that point sizeof tells you the size of the pointer, not the length of the array. If it is a null terminated string you could use strlen to find the length of the content, but that may not be the length of the actual array. https://stackoverflow.com/questions/492384/how-to-find-the-sizeof-a-pointer-pointing-to-an-array – Retired Ninja Nov 11 '17 at 02:59
  • @Someprogrammerdude: It is actually the lifetime of the `newArray` object that matters, not the scope of its name. Scope is **where** a **name** is visible. Lifetime is **when** an **object** exists. – Eric Postpischil Nov 11 '17 at 03:52
  • By the way, I suspect the OP is not compiling this with a modern standard C version. I do not see any expression in their code that would generate that error about a constant value. But, if they are using a version of C that does not support variable length arrays, they would get that error on the `newArray` declaration because it uses a run-time value for the dimension. So the reason the OP got the error is actually unrelated to the fact that `sizeof(array)` does not produce the size of the “array.” – Eric Postpischil Nov 11 '17 at 03:58
  • Or, more likely, they are compiling as C++, not C, in spite of their tag on the question and the title. – Eric Postpischil Nov 11 '17 at 04:15

2 Answers2

4

It's because passing an array to a function actually passes a pointer, so sizeof is giving you the size of a pointer instead of the size of the array, a simple solution is

char *test(char *array, size_t current_size, size_t expand_size)
{
    char string[current_size + expand_size + 1];
    // Rest of your code
}

But then, it would be a mistake to return the array string from this function, as it's only valid within the function.

I think you need to read about memory allocation, arrays and pointers before you continue your coding in c, because it's clear that you don't have the required knowledge yet.

Also, in general you should avoid strncpy() because a null terminator is not guaranteed with that function, it turns out to be very easy to end up with a non-null terminated array that you will assume is a string but it's of course, not.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
0

I find two errors in your code.

First, passing an array to a function is exactly passing a pointer to the first element in the array. So sizeof(array)returns the size of a pointer, not the whole array.

Second, the array in a function is stored in a stack, it will be destroyed after the program left the function. You can't get anything but errors when returning an array which is created by char newArray[size].

Here is my code which may help you:

#include <stdlib.h>
#include <string.h>

char *NewArray(char arr[], int arr_size, int expand_size)
{
    int new_size = arr_size + expand_size;
    char *new_arr = malloc(sizeof(char) * new_size);
    strncpy(new_arr, arr, new_size * sizeof(char));

    return new_arr;
}
K.Q D
  • 1
  • 2
  • 1
    A minor note: You use `sizeof(char) * new_size` to calculate the size passed to `malloc` but only `new_size` for the size passed to `strncpy`. They are the same with `char`, of course, but it might be nice to use the same style in both places—either use `sizeof(char) * new_size` to make the sizing explicit and prominent in case the type is ever changed or use `new_size` in both places for brevity. Or perhaps `sizeof *arr * new_size` so the size automatically changes if the array type is ever changed. – Eric Postpischil Nov 11 '17 at 04:01
  • "*You can't get anything but errors when returning an array which is created by `char newArray[size]`*" True, but the OP does not do this, so why mentioning it? – alk Nov 11 '17 at 08:34