Thread: Two Pointer Questions

  1. #1
    Registered User
    Join Date
    Mar 2008
    Posts
    15

    Two Pointer Questions

    I have a C application that uses malloc and free to allocate and free memory. Yes..old fashioned, regular c, using the gcc compiler.
    I have a function that creates a structure in memory using malloc and another to print out this structure.

    1) I had an issue where I would create the structure (worked fine) but when I called the describe function the program crashed. I restarted it and the same thing happened. I didn't make any changes except some printf's to see where it was crashing (about 10 hours later) and everything worked fine. I'm afraid this bug will come up again.

    2) Do I need to free memory when I create a string/char array like this:
    char *str = "hello world";

  2. #2
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by chris.r View Post
    1) I had an issue where [...] except some printf's to see where it was crashing (about 10 hours later) and everything worked fine. I'm afraid this bug will come up again.
    Yes. You have overwritten part of the stack inside the function. Post the code.

    2) Do I need to free memory when I create a string/char array like this:
    char *str = "hello world";
    No, try it.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  3. #3
    Registered User
    Join Date
    Mar 2008
    Posts
    15
    Is there a limit to how much memory you can allocate?
    I'd rather not post the code if I don't have to. There's quite a bit of it relating to allocating memory...

    *edit*
    On the other hand, I think it may be screwing up somewhere here...
    Code:
    struct _Table *CreateTable(int storageSize)
    {
      int count=0;
      struct _Table *tbl = (struct _Table*)malloc(sizeof(struct _Table));
      tbl->StorageSize = storageSize;
      tbl->Items = (struct TableItem**)malloc(sizeof(struct TableItem*)*storageSize);
      for (count=0; count<storageSize; count++)
      {
        tbl->Items[count] = NULL;
      }
      return tbl;
    }
    Last edited by chris.r; 06-04-2010 at 05:56 AM.

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Yes, you can only allocate as much memory as you have available virtual memory. 2 GB on Windows (x86).
    And no, we can't help you if you don't post your code.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by chris.r View Post
    On the other hand, I think it may be screwing up somewhere here...
    That code looks fine to me, altho it depends on what you think you have allocated for, eg:

    Code:
      tbl->Items = (struct TableItem**)malloc(sizeof(struct TableItem*)*storageSize);
      for (count=0; count<storageSize; count++)
      {
        tbl->Items[count] = NULL;
      }
    So this is an array of pointers that presumably later will point to actual, separately allocated, structs. Obviously, don't use the pointers themselves as structs.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    Registered User
    Join Date
    Mar 2008
    Posts
    15
    Then there's also this container...
    Code:
    struct _Container *CreateContainer(char *name)
    {
      struct _Container *g = (struct _Container*)malloc(sizeof(struct _Container));
      strcpy((char*)&g->Name, name);
      g->Tbl = CreateTable(10);
      return g;
    }
    And of course, the infamous hash table set function...
    Code:
    void *Set(struct _Table *table, char *key, int keyLength, void *value)
    {
      void *prevValue = NULL;
      int index = Hash(key, keyLength) % table->StorageSize;
      // if there is no item in the first bucket at the index
      if (table->Items[index] == NULL)
      {
        struct TableItem *item = (struct TableItem*)malloc(sizeof(struct TableItem*));
        item->Value = value;
        item->NextItem = NULL;
        strcpy((char*)&item->Key, key);
        table->Items[index] = item;
        printf("Set item at index %d in condition 1.\n", index);
        return NULL;
      }
      struct TableItem *iter = table->Items[index];
      int found = 0;
      // if the item in the first bucket has the same key
      if (strcmp(table->Items[index]->Key, key) == 0)
      {
        found = 1;
        prevValue = table->Items[index]->Value->Value;
        table->Items[index]->Value->Value = value;
        printf("Set item at index %d in condition 2.\n", index);
      }
      // otherwise look for the item in the list at the index
      while (iter->NextItem != NULL && found == 0)
      {
        iter = iter->NextItem;
        // if we found the item in the list at the index
        if (strcmp(iter->Key, key) == 0)
        {
          found = 1;
          prevValue = iter->Value->Value;
          iter->Value->Value = value;
          printf("Set the item at %d in condition 3.\n", index);
        }
      }
      // if the item doesn't exist in the list at the index
      if (found == 0)
      {
        struct TableItem *item = (struct VertexTableItem*)malloc(sizeof(struct TableItem*));
        item->Value = value;
        item->NextItem = NULL;
        Copy((char*)&item->Key, key, keyLength);
        iter->NextItem = item;
        printf("Set the item at %d in condition 4.\n", index);
      }
      return prevValue;
    }
    Aaaaand don't forget the Print function. This is where the program is crashing.
    Code:
    void PrintTable(struct _Table *table)
    {
      int index=0;
      for (index=0; index < table->StorageSize; index++)
      {
        struct TableItem *item = table->Items[index];
        if (item != NULL)
        {
          do {
            printf("%p->", item);
            item = item->NextItem;
          } while (item != NULL);
        }
        printf("NULL\n");
      }
    }
    Last edited by chris.r; 06-04-2010 at 06:22 AM.

  7. #7
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Code:
        struct TableItem *item = (struct TableItem*)malloc(sizeof(struct TableItem*));
    is enough to crash.
    Its best to use
    Code:
           struct Table *item = malloc( sizeof(*item) );
    Last edited by Bayint Naung; 06-04-2010 at 07:10 AM.

  8. #8
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    One problem with using printf is that stdout is buffered by default. That means data can be left in the buffer (and not printed out) when the crash occurs, possibly misleading you. You should always used one of these for debugging:
    Code:
    printf("blah blah"); fflush(stdout);
    fprintf(stderr, "blah blah");
    The second one works because stderr is not buffered. Supposedly puts() uses stderr but I have seen fprintf(stderr) statements made after a puts() statement get output first, so I won't recommend puts().

    More seriously, it's probably about time you started to learn to use a debugger, which can make some problems of this sort much easier to solve. Here's a simple example of that using gdb:

    getting a segfault using pointers

    For example, in that print function:
    Code:
    void PrintTable(struct _Table *table)
    {
      int index=0;
      for (index=0; index < table->StorageSize; index++)
    If *table is NULL, seg fault here. Unrelated style point:
    Code:
        if (item != NULL)
        {
          do {
            printf("%p->", item);
            item = item->NextItem;
          } while (item != NULL);
        }
    is the same as the simpler:
    Code:
    while (item != NULL) {
             printf("%p->", item);
             item = item->NextItem;
    }
    The two commands you will want to make use of in gdb right now are "bt" (for backtrace) and "print" with which you could check whether table is NULL or not (if you segfault inside PrintTable, try "print table" in gdb afterward). Also you may need "up" -- if the segfault happens inside a library and the backtrace leads into your program (it will), you can't print any of the variables in the offending function until you move "up" into it.
    Last edited by MK27; 06-04-2010 at 06:51 AM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  9. #9
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    MK27, puts() writes to stdout.
    You can change stream buffer mode using setvbuf function.
    Usually stdout is line buffered.

  10. #10
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Not related to the problem at hand, but I'd like to point out that identifiers that begin with an underscore followed by a capital letter are reserved for the implementation. That means it's undefined behavior to create something called "struct _Container", for example. The implementation is perfectly free to define a macro called _Container that breaks your struct, and it'd be your fault, not the implementation's.

    The fact that it works for you doesn't mean that the code is correct; it merely means that you're not stepping on your particular implementation's toes. I would highly recommend renaming your struct tags; it'll make your code more portable, and more correct.

  11. #11
    Registered User
    Join Date
    Mar 2008
    Posts
    15
    What do you mean by the implementation?

    I'm currently defining my structures like this: typedef struct _Name {} Name;
    My plan for using these structures outside the library was to use the "Name" instead of "struct _Name"

  12. #12
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Implementation refers to the code the compiler vendor has created. Your C standard library. Mostly code that you don't see. Internal stuff that makes all the public functions go around.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  13. #13
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Quote Originally Posted by chris.r View Post
    What do you mean by the implementation?

    I'm currently defining my structures like this:
    Code:
    typedef struct _Name {} Name;
    My plan for using these structures outside the library was to use the "Name" instead of "struct _Name"
    The implementation is, basically, compiler plus C library.

    The problem with doing things the way you are is that your compiler is free to do something like
    Code:
    #define _Name 1
    You can see how that might mess up your struct definition.

    The implementation needs to be able to create identifiers (that is, variable names, etc) for various internal things it does. But it can't just pick any old names for them, because that could clash with your code. So the implementation has been given all of the identifiers that start with an underscore and an upper letter (among others) to do with as it pleases. You, the programmer, are not supposed to use these names. This way there is a clear separation between you and the implementation: you won't step on its toes, it won't step on yours.

    Unfortunately, the compiler's not required to tell you when you've invaded its namespace like that (it may be difficult or impossible for it to do so). This is just one of those things you have to remember.

  14. #14
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    37,978
    MK27 has some excellent ideas with "Use the debugger Luke".

    You can add to the toolbox.

    valgrind ./myprog
    Which will tell you about all sorts of illegal memory usage. You can even use it to drop into the debugger when it spots a problem.


    gcc prog.c -lefence
    Electric Fence is a malloc debug library, which arranges memory so that you get a segfault as soon as you step off the end of any memory you allocated.
    Running such a program in the debugger will show you the exact line of code trying to access past the end of its allocation.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Pointer to a function pointer
    By @nthony in forum C Programming
    Replies: 3
    Last Post: 05-30-2010, 05:13 PM
  2. Basic Char and Pointer questions
    By maskedMan in forum C Programming
    Replies: 3
    Last Post: 11-11-2009, 10:33 AM
  3. towers of hanoi problem
    By aik_21 in forum C Programming
    Replies: 1
    Last Post: 10-02-2004, 01:34 PM
  4. Quick question about SIGSEGV
    By Cikotic in forum C Programming
    Replies: 30
    Last Post: 07-01-2004, 07:48 PM
  5. Another Linked List plee
    By Dragoncaster131 in forum C Programming
    Replies: 3
    Last Post: 05-15-2004, 05:40 PM