Why isn't malloc necessary here? 
Author Message
 Why isn't malloc necessary here?

My apologies for using the following Unix-related program as an
example, but as my question is a simple one pertaining purely to C, I
feel I may be forgiven.... Anyway, I've noticed that when I write
simple programs using pointers, I inevitably get core dumps unless I
use malloc to assign memory first. However, the following program,
from a book by Stevens, uses pointers with gay abandon - but never
once uses malloc or any similar function. And it doesn't dump core.
Why is this?

Thanks,

David King

/*
 * Example of server using UNIX domain stream protocol
 */

#include "uniks.h"
int readline(int, char *, int);
int writen(int, char *, int);

main(int argc, char *argv[])
{
        int                     sockfd, newsockfd, clilen, childpid, servlen;
        struct sockaddr_un      cli_addr, serv_addr;

        pname = argv[0];

        /*
         * Open a socket (a UNIX domain stream socket).
         */

        if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
                printf("server: can't open stream socket\n");

        /*
         * Bind our local address so that the client can send to us.
         */

        bzero((char *) &serv_addr, sizeof(serv_addr));
        serv_addr.sun_family = AF_UNIX;
        strcpy(serv_addr.sun_path, UNIXSTR_PATH);
        servlen = sizeof(serv_addr.sun_family) + strlen(serv_addr.sun_path);

        if (bind(sockfd, (struct sockaddr *) &serv_addr, servlen) < 0)
                printf("server: can't bind local address\n");

        listen(sockfd, 5);
        for ( ; ;) {
        clilen = sizeof(cli_addr);
        if (newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen)
< 0)
                printf("server: accept error\n");

        if (childpid = fork() < 0)
                printf("server: fork error\n");
        else if (childpid == 0) {       /* child process */
        close(sockfd);
                 str_echo(newsockfd);
        exit(0);
                                }
        close(newsockfd);
                }

Quote:
}      

/*
 * Read a stream socket one line at a time, and write each line back
 * to the sender. Return when the connection is terminated.
 */

#define MAXLINE 512

str_echo(int sockfd)
{
        int n;
        char line[MAXLINE];

        for( ; ; )
                {
        n = readline(sockfd, line, MAXLINE);
                if (n == 0)
                        return;         /* connection terminated */
                else if (n < 0)
                        printf("str_echo: readline error\n");

                if (writen(sockfd, line, n) != n)
                        printf("str_echo: writen error\n");
                }

Quote:
}

/*
 * Read a line from a descriptor. Read the line one byte at a time,
 * looking for the newline. We store the newline in the buffer, then
 * follow it with a null. We return the number of characters up to but
 * not including the null.
 */

int readline(fd, ptr, maxlen)
register int    fd;
register char   *ptr;
register int    maxlen;
{
        int n, rc;
        char c;

        for(n = 1; n < maxlen; n++)
                                        {
                if ((rc = read(fd, &c, 1)) == 1)
                                                {
                                                *ptr++ = c;
                                                if (c == '\n')
                                                        break;

                                                }
                else if (rc == 0)
                                                {
                                                if (n == 1)
                                                        return(0); /* EOF, no data read */
                                                else
                                                        break;
                                                }
                else
                        return(-1);             /* error */
                                        }
                *ptr = 0;
                return(n);

Quote:
}

/* write n bytes to a descriptor. Use in place of write()
 * when fd is a stream socket.
 */

int writen(register int fd, register char *ptr, register int nbytes)
{
int     nleft, nwritten;

nleft = nbytes;
while (nleft > 0)
                {
                nwritten = write(fd, ptr, nleft);
                if (nwritten <= 0)
                        return(nwritten);               /* error */

                nleft -= nwritten;
                ptr += nwritten;
                }
        return(nbytes - nleft);

Quote:
}



Sat, 06 Jan 2001 03:00:00 GMT  
 Why isn't malloc necessary here?

Quote:

>My apologies for using the following Unix-related program as an
>example, but as my question is a simple one pertaining purely to C, I
>feel I may be forgiven.... Anyway, I've noticed that when I write
>simple programs using pointers, I inevitably get core dumps unless I
>use malloc to assign memory first. However, the following program,
>from a book by Stevens, uses pointers with gay abandon - but never
>once uses malloc or any similar function. And it doesn't dump core.
>Why is this?

>Thanks,

If you're using pointers in your program to what data do you let it point?
After declaration a pointer does not contain valid information. You should
first let it point to some data. The two way to do this are:
    - allocating the data with malloc
    - assigning the address of some other variable

The first one is obvious. The second use can be done like this:

    int a;
    int* p_a;

    p_a = &a;

From here on you can safely use p_a as a pointer to an integer. Before
this point p_a was not initiliaze so it did not point to anything useful.

Greetings,



Mon, 08 Jan 2001 03:00:00 GMT  
 Why isn't malloc necessary here?

Quote:

> My apologies for using the following Unix-related program as an
> example, but as my question is a simple one pertaining purely to C, I
> feel I may be forgiven.... Anyway, I've noticed that when I write
> simple programs using pointers, I inevitably get core dumps unless I
> use malloc to assign memory first. However, the following program,
> from a book by Stevens, uses pointers with gay abandon - but never
> once uses malloc or any similar function. And it doesn't dump core.
> Why is this?

Perhaps because he correctly uses pointers that actually point to something?  Your perception
that you must use malloc if you are using pointers is just plain wrong - malloc and pointers
do work well together (used as directed), but pointers are much more useful than that.  Study
the code - see that wherever he uses a pointer it is actually pointing to something...  Also
(been a long time since my last foray into sockets...) some of the Unix socket calls in your
sample may actually be returning space that they've malloc'd inside the function.


Mon, 08 Jan 2001 03:00:00 GMT  
 Why isn't malloc necessary here?

Quote:

> I've noticed that when I write
> simple programs using pointers, I inevitably get core dumps unless I
> use malloc to assign memory first. However, the following program,
> from a book by Stevens, uses pointers with gay abandon - but never
> once uses malloc or any similar function. And it doesn't dump core.
> Why is this?

The important point is that a pointer, before any real use, must
be initialized to point to validly-allocated memory.  In general,
there are *two* ways to do this -- either initialize the pointer
with the "address of" some object which the compiler has
allocated for you, or initialize it by calling malloc.

For example, if we have a character pointer which we wish to
initialize to point to a chunk of memory suitable for storing 100
chars, we could either do

        char a[100];
        char *p = a;
or
        char *p = malloc(100);

These aren't precisely equivalent, of course.  When we set p
pointing at the array, we can use only a fixed-size array
(the number 100 is fixed at compile time).  Although the compiler
essentially allocates the array for us, it may also deallocate
it -- if the array is an automatic (local) variable.  Therefore,
if a[] is local to some function f(), we'd have to be careful not
to use the value of p after f() returned.

When we set p by calling malloc, on the other hand, the number
100 is not fixed; it could be the value of a variable whose value
was not determined until run time.  We'd have to be careful -- by
checking malloc's return value for NULL -- to ensure that malloc
succeeded before using p.  And the storage allocated my malloc
would persist for as long as we liked -- but we would be
responsible for freeing it if/when it was no longer needed.

If you now reexamine Steven's code, I think you'll find that
every pointer ends up being initialized to point at some
compiler-allocated object.  Often, though, this initialization
is "hidden" across a function call.  For example, we might have

        char a[100];
        f(a);

        ...

        f(char *p)
        {
        ...

When called as f(a), the pointer variable p within f() ends up
pointing within the array a.

Arrays are not the only compiler-allocated objects which can
be used for initializing pointers.  When you're working with
structures, it's not unusual to use a single compiler-allocated
instance of a structure as the "buffer" to be pointed to by a
structure pointer.  For example, we might have

        struct x one_x;
        struct x *xp = &one_x;

Again, this is roughly equivalent (though with the same
differences as outlined above) to

        struct x *xp = malloc(sizeof(struct x));

Finally, you should be aware that some of the pointer syntax         ,
in Stevens's code (e.g. the sockaddr stuff) involves some rather outre
casts which might be considered poor style except that they're
essentially mandated by the Berkeley socket interface.
(Actually, in Berkeley's defense, what they're trying to
accomplish with those casts is essentially inheritance, which
would of course be possible to implement, without goopy casts,
in a language with formal support for OOP.)

                                        Steve Summit



Mon, 08 Jan 2001 03:00:00 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. volatile isn't necessary, but it's there

2. Why is (typedef)malloc() necessary....

3. NULL isn't 0/0 isn't NULL

4. why isn't stdio full-duplex?

5. Top Left Icon - Why Isn't it Showing Up Correctly

6. HELP - why isn't ld working

7. why isn't there a strcasestr ?

8. Why isn't there a ->= operator?

9. Why isn't this working?

10. Why isn't there a logical XOR?

11. Why isn't one interface registered?

12. Why isn't ICollectionOnSTLImpl thread-safe?

 

 
Powered by phpBB® Forum Software