0

I'm new to c and attempting socket programming. I have a question about pointers.

Say I have a setup like this:

int main() {
    ... // some code
    int numbytes = receive(i); 
}

int receive(int num) {
    ... // some code
    msgLength = ... // some code
    char msgWithLength[4 + msgLength]; 
    int n = getMsg(clientSocket, msgWithLength, 4 + msgLength);
    char * msg = unpack(msgWithLength, 4);
    return n; 
}

char * unpack(char *msgWithHeader, int headerSize) {
    char *msg = ... // some code to remove header from msgWithHeader
    return msg;
}

What I want is to access msg in in main. I don't want recieve to return msg though, I want it to return an int. Also, in main, I don't know the size of msg.

Ideally I'd have something like

int main() {
    char * msg;
    int numbytes = receive(i, msg); 
    // And be able to access msg here
}

But this doesn't work. I guess my question is related to pointers and passing by reference. Any ideas on how to get this to work?

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
Asool
  • 13,031
  • 7
  • 35
  • 49
  • "I don't want recieve to return msg though" - You can't have the cake and eat it. Maybe before starting socket programming getting the language basics is a good idea. One would be to know C is not C++, so not to spam tags. – too honest for this site May 21 '17 at 15:54
  • Start by reading up on pass by reference. I recommend you read it in a proper textbook, online or otherwise. The issue is too fundamental to be classified as a *specific programming problem*, which is what this site is about. The next topic you will definitely need to read about is *heap allocation* which is again too broad to explain here from scratch. – n. m. could be an AI May 21 '17 at 15:59
  • @n.m.: C does not support pass-by-reference. – too honest for this site May 21 '17 at 16:17
  • @Olaf (1) The question was initially tagged with bith C and C++ tags. (2) C supports the abstract *concept* of pass-by-reference jolly well despite lacking a concrete *construct* that directly implements said concept. – n. m. could be an AI May 21 '17 at 16:24
  • @n.m.: A pointer is not a reference, but a first-class type. All paramters and results are passed by value, not by reference. And the text makes clear OP uses C, so the double-tagging was once more spamming, as it seems to be typical for beginners. Wrt abstract concepts: Assembly language also allows to implement the abstract concept of OOP, yet it des not _support_ it, i.e. with language constructs. And no one would consider it an OOP language. – too honest for this site May 21 '17 at 16:28
  • @Olaf (1) You are talking about language constructs. I am talking about language-independent concepts. There is an important difference between the two notions. (2) Since OP doesn't seem to have a good grasp of either language, inferring their intent from something that resembles code would be premature. Indeed the presented fragments are neither valid C nor valid C++. – n. m. could be an AI May 21 '17 at 16:38
  • @n.m.: I talk about language **support**. On a turing complete language this obviously implies language features! And strictly speaking: C does not really enforce references, as they are not a first-class type. You can emulate them, but not really enforce immutability of the underlying pointer, nor avoid explicitly dereferencing it. Both are basic propeties of references. – too honest for this site May 21 '17 at 16:42
  • @Olaf If somebody asked you how to do OOP in the assembly language, the answer "assembly language doesn't support OOP" would be misleading and unwanted. – n. m. could be an AI May 21 '17 at 16:42
  • @n.m.: So you better don't ask. (I really had no idea, you speak for all people in the world. Or do you just think your opinion is the only correct?) – too honest for this site May 21 '17 at 16:47
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/144787/discussion-between-n-m-and-olaf). – n. m. could be an AI May 21 '17 at 17:07

2 Answers2

1

You have to pass a pointer to your variable in C in order to "pass by reference". To get data into a char * variable from a function that you call, the function has to take the address of your char *. The syntax for the address of a character pointer looks like: char** (one asterisk to represent a pointer, and the other asterisk to show that the pointer is pointing to a "char *", a character pointer variable). The value given to the "char * *" parameter is the address of your char * variable : &msg. Then inside the function you dereference the char ** variable - *address_of_msg - to assign to the msg variable that is external to the function.

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

int receive(int a, char **address_of_msg)
{
  *address_of_msg = malloc(200);
  strcpy(*msg,"modified in subroutine");
  return 10;
}

int main(void)
{
  char *msg;
  int return_value;
  return_value = receive(20,&msg);
  printf("return value: %d msg: %s\n",return_value,msg);
}
Scooter
  • 6,802
  • 8
  • 41
  • 64
1

It's perfectly normal to do something like that with pointers. But it can be a bit tricky. If the function does the memory allocation, you will have to pass a pointer to a pointer as an argument, which is possible, but not very common. The Apache Portable Runtime library makes use of this technique.

It is more common to pass a pointer to a buffer and the size of the buffer as arguments, like so:

int your_read(int fd, char *buf, size_t len) {
    return read(fd, but, len);
}
// called using e.g.:
char the_buffer[1024];
your_read(0, the_buffer, sizeof(the_buffer))

If you do want to do something similar to what I described first, it would be:

int create_object(struct example **e) {
    *e = malloc(sizeof(**e));
    if (*e == NULL)
        return -1;
    (*e)->name = "example";
    return 0;
}
// called using:
struct example *the_example;
create_object(&example);
Cheatah
  • 1,825
  • 2
  • 13
  • 21