-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,929
  • 1
  • 12
  • 28
  • @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. 'pronouns' 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. 'pronouns' 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. 'pronouns' 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. 'pronouns' 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. 'pronouns' 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. 'pronouns' 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,368
  • 2
  • 25
  • 27
  • 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___________
  • 34,740
  • 4
  • 19
  • 48
  • This is horrible code. What on god's green earth is it supposed to do? Why the cast? Why the curly braces? None of this is needed. – n. 'pronouns' m. Mar 09 '19 at 11:38
  • @n.m. have you ever heard about the compound literals? Probably not if you do not know this syntax. This "horrible" syntax comes from the C standard :D – 0___________ Mar 09 '19 at 11:40
  • 2
    @n.m. - That is a compound literal, in lieu of a named variable. But I agree this is unlikely to pass code review. – StoryTeller - Unslander Monica Mar 09 '19 at 11:40
  • 1
    @P__J__ I know the syntax. It is not needed here. The only thing it does is muddying the waters. – n. 'pronouns' m. Mar 09 '19 at 11:41
  • @StoryTeller it is answer for the OPs questions. BTW CL are more and more popular and it 100% safe and correct code – 0___________ Mar 09 '19 at 11:42
  • @n.m. so please five me an example how in the function call pass this pointer to pointer. – 0___________ Mar 09 '19 at 11:43
  • 1
    Correct it may be. Readable and easy to maintain down the line it is not. So I'd reject it in code review in favor of a named variable, since the two will produce virtually the same machine code – StoryTeller - Unslander Monica Mar 09 '19 at 11:46
  • 1
    @StoryTeller - but the question is: how to do not have this additional line. You opinion is not important as the question is how to avoid that line. And my answer is actually giving the correct solution. Those comments are off the question topic. – 0___________ Mar 09 '19 at 11:49
  • You want to dereference the pointer, take the xth element of the resulting array, and pass around its address. Either `&(*str)[x]` or `*str + x` will do. No casts or compound literals are needed, or make sense indeed. – n. 'pronouns' m. Mar 09 '19 at 11:50
  • SO is not just about "answering the question". It's about added value and quality solutions. So I'm very much on topic. – StoryTeller - Unslander Monica Mar 09 '19 at 11:51
  • PJ is right, but I have to say that their opinions do matter a lot. People learn from this. – Edenia Mar 09 '19 at 11:51
  • @StoryTeller Yes. And while his answers the question, it is safe to say it is not a good code. But `pointer + x` does not work. I've posted the code I test on. – Edenia Mar 09 '19 at 11:53
  • 1
    @n.m. both are wrong as OP wants `char **` not the `char *` - so you are wrong I afraid. – 0___________ Mar 09 '19 at 11:54
  • Yes it looks like you are right, it's all my mistake. – n. 'pronouns' m. Mar 09 '19 at 12:10
  • Of course bad buildable code is worse. It will get into someone's product and stay there. Can't say that about non-working code. – n. 'pronouns' m. Mar 09 '19 at 12:30
  • PJ, he is not criticizing you, he sees a code and criticizes code. Now "horrible" is slightly subjective as I wouldn't call something that works "horrible" regardless of how many better options are there. (In this case there pretty much none), "Redesign your program" is a non-solution solution. Just like "Restart PC". – Edenia Mar 09 '19 at 12:45
  • It is probably a good time to stop answering the questions here. I am out – 0___________ Mar 09 '19 at 12:57
  • @ָEdenia A temporary variable would be a better option by far IMNSHO. Your interface is broken and you can try living with it or design something better, your choice. – n. 'pronouns' m. Mar 09 '19 at 13:11
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,863
  • 2
  • 16
  • 39