Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Pointer, scanner help

  1. Jan 26, 2009 #1
    What I want to do is pass in a string to read_integer (a function which will parse the string character by character, convert the characters into ints (c - '0'), store it into a struct, and return a pointer to that struct. The string is guaranteed not to be over 200 digits.). I'm not sure how to access part of the struct because the piece that is storing the ints is a int pointer with no array size, and not sure if I'm passing in references right:

    Code (Text):

    #include <stdio.h>

    struct integer
    {
       int* digits;
       int size;
    };

    struct integer* read_integer(char* stringInt);

    int main(void)
    {
       FILE* read_file;
       char intStr[200];
       struct integer* first;

       read_file = fopen("ints.txt", "r");
       fscanf(read_file, "%s", &intStr);
       first = read_integer(intStr);
       
       fclose(read_file);
       system("PAUSE");
       return 0;
    }

    struct integer* read_integer(char* stringInt)
    {
           int index;
           struct integer* new_integer;
           char iterchar;
           
           new_integer = (struct integer*)(malloc(sizeof(struct integer)));
           new_integer->size = strlen(stringInt);
           new_integer->digits = (int*)(malloc(new_integer->size * sizeof(int)));
           
           for(index = 0; index < new_integer->size; index++)
           {
              scanf("%c", &iterchar);
              new_integer->digits = (int)(iterchar - '0');
              printf("%c", iterchar);
           }
           
           return new_integer;
    }

     
     
  2. jcsd
  3. Jan 26, 2009 #2
    First off, if you don't check for a valid pointer after attempting to allocate heap memory the program will crash if you use the pointer. Secondly, when you return from read_integer(), you are not deallocating any heap memory potentially allocated, so this will cause a memory leak if you succeed. Before figuring out the logic, you should understand and implement the basics of good housekeeping.

    You can figure out what a character is relative to a digit by looking at the code page you are writing to. Usually, the digit '32' will convert between the two but not all the time.
     
  4. Jan 26, 2009 #3
    1. How do I check for a valid pointer?
    2. Should I free(new_integer) and free (new_integer->digits) after returning new_integer?
    3. How can I store parsed characters to new_integer->digits?
    4. Is any syntax or parameter passing wrong so far in my example?
     
  5. Jan 26, 2009 #4
    (1) if (pAllocatedHeapMemory == NULL)
    .............handle no memory available condition

    (2) You should reclaim all memory you allocated

    (3) Look at your code page you are writing to. What is the difference between an 'A' (or an 'a') and a '0'?

    (4) You are only passing one parameter...a char pointer. It looks OK, just make sure the memory of the characters are sequential.


    As a side note, I generally do not like to allocate memory like you are. One method allocates and another deallocates. It may be better if you pass a pointer to the 'Scan' method in the form of a valid struct pointer and allocate the memory of the struct before the call instead of in the call.
     
  6. Jan 26, 2009 #5
    In the main function i'm declaring char intStr[200]; and first = read_integer(intStr); but the function struct integer* read_integer(char* stringInt) requires a character pointer, and I'm not passing in a pointer, this is fine?

    Also would this work for converting/storing in ints if stringInt is guaranteed to have character glyph 1 through 9:

    Code (Text):

      struct integer* read_integer(char* stringInt)
    {
       int index;
       struct integer* new_integer;
       
       new_integer = (struct integer*)(malloc(sizeof(struct integer)));
       new_integer->size = strlen(stringInt);
       new_integer->digits = (int*)(malloc(new_integer->size * sizeof(int)));
           
       for(index = 0; index < new_integer->size; index++)
       {
          new_integer->digits = (int)(stringInt[index] - '0');
       }
           
       return new_integer;
       
       free(new_integer);
       free(new_integer->digits);
    }
     
     
  7. Jan 26, 2009 #6
    You are passing a pointer...a pointer to the first memory address in the array. This appears OK. As a rule, I never use a passed in pointer until I check it for validity because someone else may have wrote the other code, or I may have made an undiscovered error previously. Either way, the program will crash if using an invalid pointer. Your free() calls are not invoked. As I mentioned before, I would not worry about your logic until you learn how to implement good housekeeping. When you get to the logic, look at your code page.

    Do you have a debugger
    ?
     
  8. Jan 26, 2009 #7
    Thanks for your help.

    I don't know what you mean by code page, do you mean ASCII table?

    I'm using DevC++ IDE and the program compiles and runs ok, but on run-time I get an error in the console: C:\Users\Sean\Documents\bigint.c [Warning] assignment makes pointer from integer without a cast on the line: new_integer->digits = (int)(stringInt[index] - '0');

    This is for a computer science class teaching us the basics of structs, pointers, and dynamic memory allocation... this is the first program and it seems really hard for me.

    What do you mean my free() calls are not invoked, does the program not get that far in run-time?
     
  9. Jan 26, 2009 #8
    You are returning before the free() calls are invoked. Even if they were invoked you would be returning a NULL pointer since you are trying to free the memory. I realize you are attempting to follow my thoughts by placing the allocation and deallocation in the same method. You might try allocating and deallocating the memory in the main() method and then send as a parameter a pointer to the struct. If you did this, you could just return a boolean value representing failure or success. Generally, there is no need for another method unless you intend to share the method with other code or you are building a library.

    You could be supporting ACSII, ANSI, UNICODE, etc. and the libraries you have at your disposal (such as a call to atoi()) would depend upon the logic needed to parse a character and convert to an integer. So far, you have not dislosed this, unless I missed it.

    I use Visual C++ so I am guessing here. The warning of your compiler sounds like you are not casting the '0'. Does this give you a warning?

    new_integer->digits[nIndex] = (int)((char)stringInt[index] - (char)'0');

    If it still does, play around with the parenthesis. It sounds like you are missing a cast.

    Overall, the main thing is to keep being persistent. These computers are very dumb. You just have to figure out the leverage.
     
    Last edited: Jan 26, 2009
  10. Jan 26, 2009 #9

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    What's with the italics? Are you trying to make your responses hard to read?

    Logic is more important than housekeeping in introductory programming problems, which this appear to be. By harping on housekeeping, Potential, you missed the bigger problem (bolded below).

    1. malloc returns the NULL pointer to indicate failure. It is a good idea to check for failure in calling any routine that can fail.

    2. No. If you do that you cannot access the contents. You *should* free allocated memory when you are done using it. You *must not* free allocated before you are done using it.

    3. The statement new_integer->digits = (int)(iterchar - '0'); is the key source of your problems. You allocated the space earlier. This statement overwrites the earlier assignment. Now you need to use that allocated space by assigning into new_integer->digits rather than assigning to new_integer->digits.

    4. Your definition of and use of read_integer are fine.


    Your use of free in the revised version (post #5) is not valid. Fortunately, that code will never execute (it is after the return statement).
     
  11. Jan 26, 2009 #10
    Yeah, I don't know how to assign into this int* digits when dealing with pointers and structures. new_integer->size = strlen(stringInt) works.

    Can you give me an example?

    Thank you.
     
  12. Jan 26, 2009 #11

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    The allocated memory is essentially an array. How do you set the nth element of an array?
     
  13. Jan 26, 2009 #12
    Would this work:

    Code (Text):
    new_integer->digits[index] = (int)(stringInt[index] - '0');
    It seems that I have a NULL pointer or something because when I try to print:

    Code (Text):

    first = read_integer(integer_string);
    print(first);

    void print(struct integer* p)
    {
       int index;
       
       for(index = 0; index < p->size; index++)
       {
          printf(p->digits[index]);
       }
    }
     
    The program crashes.
     
  14. Jan 26, 2009 #13

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    Yes.

    I'm going to repeat something Potential asked in post #6: Do you have a debugger?
     
  15. Jan 26, 2009 #14
    Thanks for all the help guys.

    I got the read_integer and print_integer functions working like I want.

    I got a question though,

    1. What lib do I need for max(a,b) to work? I get linker errors when doing this: int carry[max(p->size, q->size)];
     
  16. Jan 26, 2009 #15
    When I call this function and print it returns a negative large integer. Every single time I compile and run the number changes. Can you see any logical errors in this:

    Code (Text):

    struct integer* add(struct integer* p, struct integer* q)
    {
       int index;
       int max;
       
       if (p->size > q->size)
       {
          max = p->size;
       }
       else if (q->size > p->size)
       {
          max = q->size;
       }
       else
       {
          max = p->size;
       }

       int carry[max];
       struct integer* result;
       
       result = (struct integer*)(malloc(sizeof(struct integer)));
       result->size = max + 1;
       result->digits = (int*)(malloc(result->size * sizeof(int)));
       
       for(index = 0; index < result->size; index++)
       {
          if (carry[index] + p->digits[index] + q->digits[index] >= 10)
          {
             carry[index + 1] = 1;
             result->digits[index] = carry[index] + p->digits[index] + q->digits[index] - 10;
          }
          else if (carry[index] + p->digits[index] + q->digits[index] < 10)
          {
             carry[index + 1] = 0;
             result->digits[index] = carry[index] + p->digits[index] + q->digits[index];
          }
       }
       
       return result;
    }
     
     
  17. Jan 26, 2009 #16

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    To answer your previous question, max is not in the C standard library. You can find it defined (non-standard) as a macro MAX, sometimes in math.h (but no promises; it's not standard).

    I'll answer your latter question with a hint and a question. The hint: "Every single time I compile and run the number changes." That almost always means a problem with uninitialized memory. The question: Do you have a debugger, and do you to use it?
     
  18. Jan 26, 2009 #17
    What is weird is that half of the large integer is the correct answer I want, and half of it is some random integer.

    I looked through all my code and can't find something I did not initialize.

    My IDE has a debugger but I don't know how to use it, I usually debug by putting in printf() functions.
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Have something to add?



Similar Discussions: Pointer, scanner help
  1. Java Scanner (Replies: 2)

  2. This pointer (Replies: 2)

  3. Pointers and strings (Replies: 19)

Loading...