By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
425,526 Members | 2,189 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 425,526 IT Pros & Developers. It's quick & easy.

Array capacity exceeded -- why does it still work?

P: 5
I am having difficulty understanding why the following code does not result in error. The code below simply traverses a string, extracting any continuous sequence of digits (0 - 9) and placing them into a separate array.

For example, the following string: abc1&qwerty22.xyz0321ijk5Q_ #*9
should produce the array: [1, 22, 321, 5, 9].

Given the array declaration char next_number[MAX_DIGITS], where MAX_DIGITS is defined to be 8, the number of consecutive digits that can be placed in the array is limited to 8.

However, when testing this code with the 9-digit number '123456789', it appears that this number is placed into the 8 character array without raising any exceptions. I would have expected that such a test to break the program, but it didn't. Further, when printing out the array of numbers, the number '123456789' is printed correctly; in other words, it was successfully stored somehow before being transferred to the array of numbers.

Can someone please explain why a 9-digit number can be placed into the 8 character array?

Thank you.



Expand|Select|Wrap|Line Numbers
  1. void create_array()
  2. {
  3.     /* Extracted numbers cannot exceed 8 digits */
  4.     #define MAX_DIGITS 8
  5.  
  6.     char  next_number[MAX_DIGITS];    /* temp buffer used to extract numbers */
  7.     int   index = 0;    /* stores the current position of 'next_number' */
  8.     int   iter;            /* traverses the string */
  9.  
  10.     num_count = 0;    /* stores the current position of 'series' */
  11.  
  12.     /* Traverse string extracting numbers */
  13.     for (iter = 0; iter <= strlen(string); iter++)
  14.     {
  15.         /* character is a digit */
  16.         if (string[iter] >= '0' && string[iter] <= '9')
  17.         {
  18.             /* Add digit to temp buffer */
  19.             next_number[index] = string[iter];
  20.             /* Update our position in the temp buffer */
  21.             index++;
  22.         }
  23.         /* charcter is a number delimiter (a non-digit immediately following a digit) */
  24.         else if (index > 0)
  25.         {
  26.             /* End the string */
  27.             next_number[index] = '\0';
  28.             /* Place number into array (converting to integer) */
  29.             series[num_count] = atoi(next_number);
  30.             /* Update position in number array ('series') */
  31.             num_count++;
  32.             /* Reset temp buffer */
  33.             index = 0;
  34.         }
  35.     }
  36.  
  37.     return;
  38. }
Note:

'string' and 'series' are global variables. I know they should be parsed as parameters (using pointers/references), but it has been a while since I have touched on these topics... I am slowly relearning the C language :-)
Dec 20 '06 #1
Share this Question
Share on Google+
5 Replies


100+
P: 1,646
Can someone please explain why a 9-digit number can be placed into the 8 character array?

Thank you.
Hi, welcome to the wonderful world of DIY memory management.
The tradeoff for the speed you get using c++ is that you have to handle all possible problems yourself. This is a low level language without a safety net :)

When you dimension an array the OS will allocate a contiguous block of memory. Anything could be next in line to that block. You can still access the memory after your array and heaven help you if there is code there that your app is using and you overwrite it.

If I am using an array of 20 char.

char myarray[20];

Then the memory address for the first character is myarray[0]
If I use the expression myarray[1] I am asking the OS to go to the memory address which is 1 char (1 byte or 8 bits) further along. If my array was of type long it would be 4 bytes further along. So when I use something like myarray[22] which maybe from a mistake in a loop, I am asking the OS to look at the memory address which is 22 bytes further on. There is nothing in c++ to stop me from doing this and reading that memory address will not normally cause much of a problem. If I write to that address I could be causing app failure.
Dec 20 '06 #2

Banfa
Expert Mod 5K+
P: 8,916
Specifically writing outside the bounds of an array in C/C++ produces undefined behaviour (which is a specified type of behaviour).

Undefined behaviour is, surprisingly, not defined as anything. A program exhibiting undefined behaviour may

1. Work as expected
2. Fail with an error logically consistent with the error (i.e. procude an out of bounds memoary access exception).
3. Do anything else you can think of, for example format the harddisk.

You should avoid undefined behaviour, it is BAD.

The problem you have come accross is that sometimes 1 happens which can result in you not noticing the error in the code. However since the behaviour is undefined the same code may produce radically different result on different systems.

The are tools out there to help track this sort of thing, static analysis tools such as Purify or splint.
Dec 20 '06 #3

P: 27
actually u should compare the value of 'iter' itself not array[iter]
u dont bother about whats inside it as long as u made ur validations before
Dec 20 '06 #4

Banfa
Expert Mod 5K+
P: 8,916
actually u should compare the value of 'iter' itself not array[iter]
u dont bother about whats inside it as long as u made ur validations before
I do not think you have read the problem and code correctly, I can not see how this comment applies to the posted problem.
Dec 20 '06 #5

P: 5
Thank you... it's all beginning to come back to me :-)

For completeness, here is my corrected code. For those of you who are more senior programmers, I would very much appreciate feedback with regards to my programming style and choice of implementation. How would have you done things different?


Expand|Select|Wrap|Line Numbers
  1. /******************************************************************************
  2.  * create_array() -- Creates an array of numbers (series) by extracting the   *
  3.  *                   numerical values from a string of characters.            *
  4.  *                                                                            *
  5.  * [Preconditions]                                                            *
  6.  *                                                                            *
  7.  * string_ptr    --    String used to create the series (array) of values.    *
  8.  * string_len    --    Length of the string.                                  *
  9.  * series_ptr    --    The array to be created from the string.               *
  10.  *                                                                            *
  11.  * [Postconditions]                                                           *
  12.  *                                                                            *
  13.  * series_ptr    --    Series of extracted numerical values from string.      *
  14.  * count_ptr     --    Number of values in the series.                        *
  15.  ******************************************************************************/
  16. void create_array(char *str_ptr, int str_len, float *series_ptr, int *count_ptr)
  17. {
  18.     #define MAX_DIGITS 8                /* ignore numbers with more digits */
  19.  
  20.     char  next_number[MAX_DIGITS+1];    /* buffer used to extract numbers */
  21.     int   index = 0;                    /* stores buffer position */
  22.     int   str_iter;                     /* used to traverse string */
  23.     int   commit = TRUE;                /* used to ignore large numbers */
  24.     int   decimal_number = FALSE;       /* determines if number is decimal */
  25.  
  26.     /* Initially, there are no numbers in the series */
  27.     *count_ptr = 0;
  28.  
  29.     /* Traverse string extracting numeric values */
  30.     for (str_iter = 0; str_iter <= str_len; str_iter++)
  31.     {
  32.         /* Digit */
  33.         if (*(str_ptr + str_iter) >= '0' && *(str_ptr + str_iter) <= '9')
  34.         {
  35.             /* Ensure the array is not already full */
  36.             if (index < MAX_DIGITS)
  37.             {
  38.                 /* Append digit to array */
  39.                 next_number[index] = *(str_ptr + str_iter);
  40.                 /* Update buffer position */
  41.                 index++;
  42.             }
  43.             /* Overflow */
  44.             else
  45.             {
  46.                 /* Ignore the number */
  47.                 commit = FALSE;
  48.             }
  49.         }
  50.         /* Minus sign (-) */
  51.         else if (*(str_ptr + str_iter) == '-')
  52.         {
  53.             /* Check if a digit proceeds -> new negative number */
  54.             if (*(str_ptr + str_iter+1) >= '0' && *(str_ptr + str_iter+1) <= '9')
  55.             {
  56.                 /* If the buffer already contains a number commit it */
  57.                 if (index > 0)
  58.                 {
  59.                     /* Ensure buffer can be committed (i.e. no overflow) */
  60.                     if (commit == TRUE)
  61.                     {
  62.                         /* Mark the end of the number */
  63.                         next_number[index] = '\0';
  64.                         /* Add the next number to the series */
  65.                         *(series_ptr + *count_ptr) = atof(next_number);
  66.                         /* Update the series position */
  67.                         (*count_ptr)++;
  68.  
  69.                         /* Begin a new (negative) number */
  70.                         next_number[0] = '-';
  71.                         index = 1;
  72.  
  73.                         /* Reset decimal flag */
  74.                         decimal_number = FALSE;
  75.                     }
  76.                     /* Current buffer content previously overflowed */
  77.                     else
  78.                     {
  79.                         /* Begin a new (negative) number */
  80.                         next_number[0] = '-';
  81.                         index = 1;
  82.  
  83.                         /* Reset the 'commit' flag */
  84.                         commit = TRUE;
  85.                         /* Reset decimal flag */
  86.                         decimal_number = FALSE;
  87.                     }
  88.                 }
  89.                 /* Otherwise, begin a new (negative) number */
  90.                 else
  91.                 {
  92.                     /* Add a minus sign to the start of the buffer */
  93.                     next_number[0] = '-';
  94.                     /* Update buffer position */
  95.                     index = 1;
  96.                 }
  97.             }
  98.         }
  99.         /* Decimal */
  100.         else if (*(str_ptr + str_iter) == '.')
  101.         {
  102.             /* Ensure buffer is not empty and number hasn't overflowed */
  103.             if (index > 0 && commit == TRUE)
  104.             {
  105.                 /* If the character proceeding is not a digit -> delimiter */
  106.                 if (*(str_ptr + str_iter+1) < '0' || *(str_ptr + str_iter+1) > '9')
  107.                 {
  108.                     /* Mark the end of the number */
  109.                     next_number[index] = '\0';
  110.                     /* Add the number to the series */
  111.                     *(series_ptr + *count_ptr) = atof(next_number);
  112.  
  113.                     /* Update the series position */
  114.                     (*count_ptr)++;
  115.                     /* Reset the 'next number' position */
  116.                     index = 0;
  117.                     /* Reset decimal flag */
  118.                     decimal_number = FALSE;
  119.                 }
  120.                 /* If the buffer already contains a decimal -> delimeter */
  121.                 else if (decimal_number == TRUE)
  122.                 {
  123.                     /* Mark the end of the number */
  124.                     next_number[index] = '\0';
  125.                     /* Add the number to the series */
  126.                     *(series_ptr + *count_ptr) = atof(next_number);
  127.  
  128.                     /* Update the series position */
  129.                     (*count_ptr)++;
  130.                     /* Reset the 'next number' position */
  131.                     index = 0;
  132.                     /* Reset decimal flag */
  133.                     decimal_number = FALSE;
  134.                 }
  135.                 /* Ensure number doesn't overflow */
  136.                 else if (index < MAX_DIGITS-1)
  137.                 {
  138.                     /* Add decimal to buffer */
  139.                     next_number[index] = '.';
  140.                     /* Update buffer position */
  141.                     index++;
  142.                     /* Set 'decimal' flag*/
  143.                     decimal_number = TRUE;
  144.                 }
  145.                 /* Number overflowed */
  146.                 else
  147.                 {
  148.                     /* Ignore number */
  149.                     commit = FALSE;
  150.                     /* Reset decimal flag */
  151.                     decimal_number = FALSE;
  152.                 }
  153.             }
  154.         }
  155.         /* Number delimiter */
  156.         else if (index > 0)
  157.         {
  158.             /* Add number in buffer to series */
  159.             if (commit == TRUE)
  160.             {
  161.                 /* Mark the end of the number */
  162.                 next_number[index] = '\0';
  163.                 /* Add the next number to the series */
  164.                 *(series_ptr + *count_ptr) = atof(next_number);
  165.  
  166.                 /* Update the series position */
  167.                 (*count_ptr)++;
  168.                 /* Reset the 'next number' position */
  169.                 index = 0;
  170.                 /* Reset decimal flag */
  171.                 decimal_number = FALSE;
  172.             }
  173.             /* Number overflowed -- reset the buffer and flags */
  174.             else
  175.             {
  176.                 /* Reset the 'commit' flag */
  177.                 commit = TRUE;
  178.                 /* Reset the 'next number' position */
  179.                 index = 0;
  180.                 /* Reset decimal flag */
  181.                 decimal_number = FALSE;
  182.             }
  183.         }
  184.     }
  185.  
  186.     return;
  187. }
Dec 26 '06 #6

Post your reply

Sign in to post your reply or Sign up for a free account.