2

Purpose : My main purpose was to create a string in some kind of function , it should return an adress , by returning adress using the string in main. But I learned char array and char pointer actually using for the same purpose.

If we suppose that's true , We have these declaration :

char *arr and char arr[10] , *(arr+9)=arr[10] isn't it?

Application 1 does not work.
Application 2 does work fine.

Application 1:

#include <stdio.h> 
char *foo(char arr[]);

int main(void)
{

    char example[10];
    example=foo(example);
    printf("%s\n",example);

    return 0;   
}
char *foo(char arr[])
{
    arr[10]="attempt";

    return arr;
}

Application 2:


#include <stdio.h>
char *foo(char*);
int main(void)
{
    char *example;
    example=foo(example);
    printf("%s\n",example);
    return 0;
}
char *foo(char* arr)
{
    arr="attempt";
    return arr;
}
nevzatseferoglu
  • 988
  • 7
  • 18
  • If you declare `char arr[10];` (10 elements, numbered 0 to 9) then valid indices are `0` to `9`, not `10`. So `*(a + 9)` is valid, but `*(a + 10)` is not. – Rudy Velthuis Feb 16 '19 at 14:44
  • Sorry It is true , I am going to edit it. – nevzatseferoglu Feb 16 '19 at 14:45
  • if you try to compile your first code example with lets say the gcc compiler, you would recieve the following error > error: assignment to expression with array type which occurs in line 8 at `example=foo(example);` –  Feb 16 '19 at 14:50
  • But assigning a string to char (be it arr[0], arr[9] or arr[10] -- they are all elements of the array, and not the array), doesn't make sense. You want to use strcpy() or strncpy() instead, to copy the string to the array: `strncpy(arr, "attempt", 10);`. – Rudy Velthuis Feb 16 '19 at 14:50
  • I know that It is possible , but I want to overcome this problem with returning the adress from function. – nevzatseferoglu Feb 16 '19 at 14:52
  • I'd expect `arr[10]="attempt";` to at least give a warning? What is your compiler/options? – chux - Reinstate Monica Feb 16 '19 at 14:52
  • and If you compile (lets say you use gcc) you will also recieve the following warning > warning: assignment to ‘char’ from ‘char *’ makes integer from pointer without a cast [-Wint-conversion] in line 14 at `arr[10]="attempt\n";` –  Feb 16 '19 at 14:53
  • Review `char *example; example=foo(example);`. What value is `foo()` given in that function call as `example` is not yet assigned a value. – chux - Reinstate Monica Feb 16 '19 at 14:55
  • This statement `arr[10]="attempt";` in the first instance of `*foo()` function should be an error in anything beyond C99. (`LLVM` gives _Error: redefinition of 'arr' with a different type: char[10] vs char *._ ) – ryyker Feb 16 '19 at 17:20

5 Answers5

3

Your code will invoke undefined behavior in both segments. ( Even though you have observed that Code 2 works, it only seems to work. In reality a failure is lurking, and can show without warning. )

Make these corrections to address that problem, and see comments for explanations:

In code 1:

//int main(void){
int main(void){//int main(void) is minimum prototype for main function.

    //char example[10];               // this will invoke undefined behavior
    char example[10] = {"something"}; // 'example' initialized with content,
                                      // thus averting undefined behavior
    //example=foo(example);
    strcpy (example, foo(example));  // char array is not assignable using `=`
                                     // use strcpy to transfer result of "foo"
    printf("%s\n",example);

    return 0;   
}
char *foo(char arr[]) //note: char arr[] decays into char *arr
{
    //char arr[10]="attempt"; // Error: redefinition of 'arr' with a 
                              // different type: char[10] vs char *

    arr = "attempt"; //because char [] decays into char *, 'arr' is usable as is.

    return arr;
}

To answer your question in comments: Why using strcpy function [after variable example was initialized] is not a undefined behaviour.
First the definition of a C string is important to know. ( C string definition is found here. )
The variable example in its original form, i.e. initialized:

char example[10];  

Can contain anything. For example:

|%|h|8|\#|d|o|-|~|*|U|?|?|?|?|
//                   ^end of memory for 'example`
// note that the character in example[9] == 'U', not NULL, therefore, not a C string.    

This would cause the function strcpy() to fail. Initializing guarantees predictable results:

char example[10] = {"something"};//properly initialized
|s|o|m|e|t|h|i|n|g|0|?|?|?|?|
//                  ^end of memory for 'example`
//or
char example[10] = {0};          //also properly initialized
|0|0|0|0|0|0|0|0|0|0|?|?|?|?|
//                  ^end of memory for 'example`
(This would require an extra step to place proper content.):
strcpy(example, "something");

The only required adjustment to Code 2 is to initialize the pointer before using: (See the reason why pointer must be initialized here.)

char *foo(char*);

//int main(void){
int main(void){//int main(void) is minimum prototype for main function.
{
    //char *example; // passing this will envoke undefined behavior
    char *example = NULL;// must initialize before using             

    example=foo(example);

    printf("%s\n",example);

    return 0;
}
char *foo(char* arr)
{
    arr="attempt";

    return arr;
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • ı knew that It was going to work with using strcpy function. Why using strcpy function is not a undefined behaviour ? – nevzatseferoglu Feb 16 '19 at 15:33
  • @SeptemberSKY - because in this case, the argument `example` has been initialized with content. Before that, the contents were undefined, meaning that it may not have been a _null terminated char array_, which is the definition of a C string. Therefore, `strcpy()` may, or may not have worked. – ryyker Feb 16 '19 at 15:39
  • 1
    In the 2nd case, `char *example = NULL;` would be sufficient. "must initialize before using, and with a value that ... ensures enough space" is unclear here. – chux - Reinstate Monica Feb 16 '19 at 15:52
1

Both do not "work" for different reasons.

The first is undefined behavior (UB) as code attempts to assign an element outside the bounds of example[10].

arr[0]='\0'; or arr[9]='\0'; would have been OK given the value passed to foo().

Converting the address of the string literal "attempt" to a char is not good code either. A well enabled compiler will warn of this basic coding lapse. @f3rmat example

char *foo(char arr[]) {
  arr[10]="attempt";  <-- UB
  return arr;
}

char example[10];
example=foo(example);

The 2nd is UB because code attempted to use an uninitialized value in passing a pointer. This "works" in that the UB of passing an uninitialized pointer is often benign. Since foo() does not use this "garbage" value and the rest of good is well defined, it "works".

char *foo(char* arr) {
    arr="attempt";
    return arr;
}
char *example;
example=foo(example);   // UB - likely a garbage value is passed to `foo()`.
printf("%s\n",example); // `example` is now pointing to `"attempt"`. 

I learned char array and char pointer actually using the same purpose.

Pointers and arrays are related, yet different. Avoid the "actually using the same purpose" idea.

An array is like a row of houses on a street. A pointer is the address of a house written on a piece of paper in your hand. Houses ≠ scrap of paper. You can refer to the house by its address or even a row of houses by the first house's address, yet a house and its address are different.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • My gcc version is : gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11) And code '2' is running on my computer. – nevzatseferoglu Feb 16 '19 at 15:19
  • @SeptemberSKY Try compiling with more warnings likes `'-Wpedantic' '-Wall' '-Wextra' '-Wconversion'`. "code '2' is running on my computer." does not mean code is without faults. Code with _undefined behavior_ may _appear_ to run well. – chux - Reinstate Monica Feb 16 '19 at 15:23
0

I tried to compile Code '1' and got the following error:

prog.c: In function ‘main’:
prog.c:8:12: error: assignment to expression with array type
example=foo(example);
prog.c: In function ‘foo’:
prog.c:14:12: warning: assignment makes integer from pointer without a cast [- 
Wint-conversion]
arr[10]="attempt\n";
        ^

You get error: assignment to expression with array type example=foo(example); because in your left hand side, you're using an array type, which is not assignable. Assignment operator (=) needs to have a modifiable lvalue as its left operand.

You get a warning: assignment makes integer from pointer without a cast [Wint-conversion] arr[10]="attempt\n"; because the left hand side and the right hand side in this assignment have different types.

Hemang
  • 11
0

Pointer and array are not the same.

char *arr = "attempt"

Here you're creating a string constant "attempt" and assigning its address to arr which is valid

char arr[10];
arr = "attempt";

This is invalid.

you can add elements to the array by following methods.

char arr[10] = "attempt";
char arr[10] = {'a', 't', 't', 'e', 'm', 'p', 't'};
arr[0] = 'a';
arr[1] = 't'; // and so on.

when you are passing the array as an argument to another function

arr = foo(arr);

you are passing the address of the zeroth element in the array arr[0]

Hope that helps..

surjit
  • 338
  • 4
  • 15
  • `char arr[10] = "attempt";` is perfectly valid, no need to separate the `char`s one by one. However, it is not what OP has done. OP has a pointer in `foo`, not an array. – Acorn Feb 16 '19 at 14:56
0

Char arrays can be initialized but cannot be assigned. char example[10]="attempt"; is valid.

But

char example[10];

example="attempt"

is not valid.

More details here

Your second example works because you pass a uninitialized pointer to a function and return an address of the string literal attempt which will work perfectly as mentioned in the answer by chux

Karthick
  • 1,010
  • 1
  • 8
  • 24