-3

Assuming there is a function like this

int foo (char** str, int x)
{
    char* p = *str + x;

    foo2(&p); // declared as int foo2 (char** );
}

(oversimplified of course, the real function is recursive and much more complicated)


I've tried to do this:

int foo (char** str, int x)
{    
    foo2(&(*str + x));
}

But the compiler failed with error:

error: lvalue required as unary '&' operand

Why did the compiler shoot out with this error and how do I pass the pointer to a pointer to string x-byte(s) forwards, without declaring a variable and use its own address?


EDIT

Seems like there is some misunderstanding so I will post a complete simulation of what I want to achieve.

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

char* string = "This is a sample string.";
char* ptr;
int randomizer;

int receive_string (char* buffer, int size) // recv
{
    int i = 0;

    if(ptr == NULL)
        ptr = string;

    for(i = 0; *ptr != '\0' && i < size; ptr++)
    {
        if(randomizer == 2)
        {
            randomizer++;

            break;
        }

        buffer[i] = *ptr;

        i++;

        randomizer++;
    }

    if(*ptr == '\0')
    {
        buffer[i] = *ptr;

        i++;
    }

    return i;
}

int read_string (char* *buffer, int size, int alloc)
{
    int bytes = 0;

    printf("Reading string..\n");

    if(*buffer == NULL && alloc == 1)
    {
        printf("Allocating buffer..\n");

        *buffer = calloc(size, sizeof(char));
    }

    bytes = receive_string(*buffer, size);

    if(bytes == (-1))
    {
        return(-1);
    }
    if(bytes == 0)
    {    
        return 0;
    }
    if(bytes < size)
    {
        char* p = *buffer + bytes;
        //int temp = read_string(&p, size - bytes, 0); // works
        //int temp = read_string(&(char *){&(*buffer)[bytes]}, size - bytes, 0); // works
        int temp = read_string(buffer + bytes, size - bytes, 0); // doesn't work

        if(temp > 0)
            bytes += temp;
        else return bytes;
    }

    return bytes;
}

int main()
{
    char* buffer = NULL;

    int bytes = read_string(&buffer, strlen(string) + 1, 1);

    printf("[%u][%s]\n", bytes, buffer);

    if(buffer)
        free(buffer);

    return 0;
}

The randomizer is the dumbest quickie to "simulate" a recv() that can not receive all bytes. This implementation simulates recv() but instead of reading from a socket queue it reads from a global string.

Edenia
  • 1,991
  • 1
  • 14
  • 31
  • @machine_1 edited the question to clarify that `foo2()` has the same set of parameters. That's why I said the original function is recursive. But if I was to make the example like that I'd have to throw a lot more code to provide a working and not deadlocking code, which is not minimal. – Edenia Mar 09 '19 at 10:53
  • Does `foo2()` modify the pointer that it's given? – user3386109 Mar 09 '19 at 11:13
  • 2
    Too many stars. Don't be a three star programmer. If a function allocates, let it **return** a pointer. – n. 1.8e9-where's-my-share m. Mar 09 '19 at 11:26
  • @n.m. Not really. The function must return something else, for e.g size. Consider functions like `recv()`. An implementation of a recv that allocates the output buffer. – Edenia Mar 09 '19 at 11:27
  • @user3386109 No. – Edenia Mar 09 '19 at 11:29
  • Is `str` an array of pointers? Do you want to pass the address of its xth element? If so, you want `&str[x]`. There is no need to abuse the pointer arithmetic notation. – n. 1.8e9-where's-my-share m. Mar 09 '19 at 11:29
  • @Edenia Then why pass the address of the pointer. Why not just pass the pointer by value. – user3386109 Mar 09 '19 at 11:30
  • 1
    So why not have it return the buffer and pass the size by reference? The less stars ina row, the easier it is to understand. Sometimes you must of course. – n. 1.8e9-where's-my-share m. Mar 09 '19 at 11:32
  • I am creating a `recv()`-like function that allocates the buffer for you and I am receiving all bytes in recursion. – Edenia Mar 09 '19 at 11:34
  • 1
    This makes no sense whatsoever. Why are you doing this? – n. 1.8e9-where's-my-share m. Mar 09 '19 at 11:40
  • `*buffer + bytes` is not freeable but you are trying to pass it to a function that may call `free` in it, this design is fundamentally broken (which is why the answers are a mess) – M.M Mar 09 '19 at 11:48
  • @n.m. I totally agree interface is confusing. That's why I posted in here. But that's how I would like to design it. – Edenia Mar 09 '19 at 11:55
  • @M.M The other function won't have `free()` it doesn't have to. It just reads and stores bytes. The API function should not free the pointer passed. It is given to the user at the end. – Edenia Mar 09 '19 at 11:56
  • 1
    @Edenia But you posted the code and it has `free(*buffer);` . – M.M Mar 09 '19 at 11:57
  • @M.M The outer function? yes it does in case of error. – Edenia Mar 09 '19 at 11:57
  • @n.m. `&(*str)[x]` causes a crash with this code. I am testing on the same code I posted. – Edenia Mar 09 '19 at 11:58
  • So you freed an address that is not freeable , `*buffer + bytes` (whose address you pass to this function). – M.M Mar 09 '19 at 11:58
  • @M.M Aha yes. Indeed. – Edenia Mar 09 '19 at 12:00
  • @M.M I removed the free and NULL code and tested again, same thing. – Edenia Mar 09 '19 at 12:00
  • `&(*buffer)[bytes]` crashes and `buffer + bytes` does not work. – Edenia Mar 09 '19 at 12:03
  • `*buffer + bytes` is of type `char*` can not pass it where it expects `char**` – Edenia Mar 09 '19 at 12:04
  • Sorry my mistake, the accepted answer is actually correct. Though it's horrible, totally unreadable code. Redesign your interface. – n. 1.8e9-where's-my-share m. Mar 09 '19 at 12:06
  • A simple `while (bytes_received < size)` could be used to fill the buffer, and you wouldn't need the `alloc` flag, and you wouldn't need recursion. – user3386109 Mar 09 '19 at 12:07
  • @user3386109 I know. I want to use recursion though. It is a bit against unix philosophy. – Edenia Mar 09 '19 at 12:08
  • @user3386109 I may create a temporal variable myself, regardless of what I use, I didn't know how to do something and I wanted to boost up my knowledge further. Stack Overflow has helped me a lot in this aspect, just like it did to many other users. – Edenia Mar 09 '19 at 12:10
  • It is not "a bit", it's *completely* against Unix philosophy. Not the recursion, but the mixing of concerns. Unix philosophy goes like that. Write a function that allocates a buffer. Write a function that reads a buffer (recursively if you want). Write a function that calls the two functions above. – n. 1.8e9-where's-my-share m. Mar 09 '19 at 12:17
  • Well, at least at the end of the day, we got the question clarified. Next time, do everyone a favor, and start with the [mcve]. Best of luck. – user3386109 Mar 09 '19 at 12:18
  • My bad, I didn't want to bother people with too much code and specificity, but it was necessary. – Edenia Mar 09 '19 at 12:20

3 Answers3

3

(*str + x) is not an lvalue as it is a temporay value that does not have an address so you cannot take its address with &. Even if the compiler stored the value in a temporary variable in RAM so its address could be taken how would you reference its value afterwards if foo2() modified the contents of the temporay variable.

Therefore you need to store the value in a temporary variable yourself.

Dipstick
  • 9,556
  • 2
  • 27
  • 28
  • Except that the other answer shows how to do without declaring a variable, but as a literal. – Edenia Mar 09 '19 at 11:25
  • 1
    @Edenia The other answer fools the compiler into allowing it to compile but doesn't solve the problen of reading the modified value if foo2() modifies`str` which is, presumably the whole point of passing a pointer to pointer rather than just passing a pointer. – Dipstick Mar 09 '19 at 11:31
  • @machine_1 Nope. Because this is a pointer arithmetic of the pointer to the pointer to string, isn't it? It's confusing. – Edenia Mar 09 '19 at 11:32
  • @Dipstick If the inner function only reads the values, isn't it ok? – Edenia Mar 09 '19 at 11:33
  • @Edenia The other answer creates an anonymous temporary variable on the stack, and passes the address of that variable to `foo2`. – user3386109 Mar 09 '19 at 11:34
  • @user3386109 Yes, but it doesn't create a variable such that I'd need an extra line. Which is good enough, as it is the only solution that get things done. – Edenia Mar 09 '19 at 11:37
  • @user3386109 first of all it is called compound literal, not the anonymous variable. Secondly the C does not know anything about the stack, stack is one of the possble implementation. Thirdly many optimizing compilers **will not** physically create this literal. – 0___________ Mar 09 '19 at 11:37
  • @edenia If the inner function only reads the value of `str` why isn't it declared `const` and why complicate matters by passing the address of a pointer to the string rather than the address of the string itself? – Dipstick Mar 09 '19 at 11:38
  • @Dipstick Because for readability reasons and code-minimalism I don't want to create more functions I'd like to use recursion, see update. – Edenia Mar 09 '19 at 11:40
  • @Edenia Nothing I've said has anything to do with the use or otherwise of recursion. – Dipstick Mar 09 '19 at 11:53
0

if you want to pass the pointer to pointer to the particular char

foo2(&(char *){&(*str)[x]});

or

0___________
  • 47,100
  • 4
  • 27
  • 62
0

I think the following code is what you are trying to do. For kicks, I made it recursive and tested it with the alphabet for a string. Variables cnt and lmt need to be global. It will show a shrinking string if you run it. Just be sure to keep p and lmt small enough to not overflow the string.

void foo(char *s, int p) {
    cnt++;
    printf("%s\n", s);
    if(cnt != lmt) foo(&s[p], p);
}
machine_1
  • 3,904
  • 2
  • 17
  • 39