0

I am writing a simple function in C that should build a char array from string "abc" – so it should build {'a','b','c'} – and return a pointer to that array. Here is my code for this function:

char * makeArr()
{
    static char arr[3];

    sprintf(arr, "%s\n", "abc");

    return arr;
}

Problems occur when I call this method in main:

int main(int argc, char *argv[])
{
    char *arr[3];

    arr = makeArr();

    return 0;
}

The compiler is complaining about casting / conflicting types. I've been playing with pointers, casting and dereferencing for quite a while now, but can't seem to get it to work. Please let me know where my logic is wrong.

freezefry
  • 138
  • 4
  • 21
  • 2
    `char *arr[3]` is an array of three `char *`. `makeArr` returns one `char *`, not an array of three of them. And incidientally, `"abc\n"` is four characters long, five with the null terminator, so you shouldn't be trying to write it into a buffer of size 3. – hobbs Oct 22 '15 at 01:03
  • @hobbs Updated my buffer size to have more than enough space. – freezefry Oct 22 '15 at 01:11
  • You forget a semicolon after `sprintf(arr, "%s\n", "abc")`. – MikeCAT Oct 22 '15 at 01:12
  • This code is wrong on so many levels... – SwiftMango Oct 22 '15 at 01:17
  • Returning a pointer to stack-allocated memory from a function is undefined behavior. You need to either pass in your pointer or dynamically allocate the space. – wickstopher Oct 22 '15 at 01:18
  • Note: a pointer to 10-element `char` array can be written like this: `char (*ptr)[10];` – MikeCAT Oct 22 '15 at 01:18
  • @wickstopher The `arr` in `makeArr()` is `static` and returning it may not be good behavior but it doesn't seem invalid. – MikeCAT Oct 22 '15 at 01:20
  • @MikeCAT you're right, I spoke too soon. it still seems like bad form. see http://stackoverflow.com/questions/453696/is-returning-a-pointer-to-a-static-local-variable-safe – wickstopher Oct 22 '15 at 01:22
  • @user3413460 please don't change *meaning* of code after you posted a question, that would be confusing to readers of comments and answers. If you want to present "corrected" code, append it in an edit. rolled back. –  Oct 22 '15 at 01:24

5 Answers5

2

Among other things, you confused:

char arr[3]; // array of 3 chars.

and,

char *arr[3]; // array of 3 pointers to char.

In main(), you should only write char *arr;

artm
  • 17,291
  • 6
  • 38
  • 54
2

Hmm ... there are several errors in this code. Let's start with the most obvious your compiler complains about:

char *arr[3];

This line declares arr to be an array of three pointers to char. What you return from your function is a single pointer to a char -> doesn't match.

Next:

static char arr[3];
sprintf(arr, "%s\n", "abc")

Here you reserve 3 chars. the sprintf() will write 5 chars. %s is replaced by the 3 characters in your string literal "abc". You add a newline character and then a 0 is added as the marker for the end of the "string". Makes 5. This btw is undefined behavior. You write past the end of your array. Code like this can be compiled, but there's no guarantee at all about what will happen at runtime.


Doing a cut here. You should read about arrays and pointers in C. If the text you're reading claims they are the same ... stop right there and find a better text. They aren't.

I'll try to explain this here briefly, so it's suitable for the Q&A style.

An array in C indeed is a contiguous space of several values. char arr[3] means a variable that holds 3 chars.

On the other hand, a char * is just a pointer pointing to a char -- this could be the first element of an array.

In C, you can't pass arrays as function parameters, and you can't return arrays from a function. Trying to do so leads to an implicit conversion: What is actually passed is a pointer to the first element of that array.

I think the last bit of information missing is what a string literal in C is: it's an array (anonymous, e.g., it doesn't have a name) containing all the characters in the double quotes plus a 0 appended. The 0 marks the end of a "string" in C.

In an expression, a string literal evaluates to a pointer to the first element.

So, something like this:

char *foo = "bar";

will lead to foo pointing to the b of the array. It's like writing

static const char no_name_0[] = { 'b', 'a', 'r', 0 };
char *foo = &(no_name_0[0]);
1

Firstly, char arr[3]; is too snall to store "abc\n". It must have at least 5 elements including terminating null-character.

Then, char *arr[3]; is a 3-element array of char*.
You should assign makeArr()'s return value (it has char* type) to arr[0] or another element, or you should change the type of arr in main function to char*, which is the same type as makeArr()'s return value.

Moreover, this makeArr() doesn't make any array and returns (a pointer to) the existing array. Yoy should use malloc() to "make an array".

UPDATE:

Assigning a value of char* to the array char arr[10]; seems invalid in C. You should use strcpy() or strncpy() (safer than strcpy()) to copy the string stored in the array between arrays.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
0

Pass the array as an argument and modify it in the called function, would be easier. If you're statically creating the array and there's no need to allocate memory, don't, just pass around your pointers to the functions to be modified by reference

void makeArr(char arr[]){
    sprintf(arr, "%s\n", "abc");
}

Simply pass the existing declared array to the makeArr function...

int main(int argc, char *argv[]) {
  char arr[10];
  makeArr(arr);
  return 0;
}
myjay610
  • 83
  • 5
0

You couldn't assign the result of makeArr to arr. I guess that's your casting error. Oversimplifying, arr points to the place on the stack where the array of 10 characters is allocated. So, I'd pass in arr to makeArr as a char*. So, you'd end up with something like this:

#include <stdio.h>
char * makeArr(char *arr)
{
    sprintf(arr, "%s\n", "abc");
    return arr;
}

int main(int argc, char *argv[])
{
    char arr[10];

    makeArr(arr);
    printf("%s\n", arr);
    return 0;
}
bruceg
  • 2,433
  • 1
  • 22
  • 29