# Newb With Small Pointer Issue

• 09-05-2004
G-Prime
Newb With Small Pointer Issue
So I'm trying to teach myself a little C by writing a program that does some simple linear algebra manipulations on a matrix. The first hurdle is figuring out how to parse an input string that is a a series integers. I found the strtol function in the GNU C Library to be just what I was looking for. So, in order to get a feel for the function, I stole an example off the GNU manual that adds up a series of integers with spaces between them.

Here is the code I'm working on right now. All it does (or is _supposed_ to do) is take input from scanf, parse the integers, and spit out their sum.

Code:

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

int errno;

int sum_ints_from_string (char *string) {
int sum = 0;
while (1) {
char *tail;
int next;
/* Skip whitespace by hand, to detect the end.  */
while (isspace (*string)) string++;
if (*string == 0)
break;
/* There is more nonwhitespace,  */
/* so it ought to be another number.  */
errno = 0;
/* Parse it.  */
next = strtol (string, &tail, 0);
/* Add it in, if not overflow.  */
if (errno)
printf ("Overflow\n");
else
sum += next;
string = tail;
}

return sum;
}

int main() {
int result;
char *p;
scanf("%[0-9 ]",&p);
result = sum_ints_from_string(p);
printf("%d\n",result);
return 0;
}

This code lets me input the string, but ends in a seg fault after the carriage return. I'm not sure what to pass to the function - all this 'pointer to a pointer' stuff that the scanf function needs has me all confused.

Thanks for helping a confused newb :)
• 09-05-2004
Prelude
Eew, what awful code.

>while (isspace (*string)) string++;
This might work if <ctype.h> were included. :rolleyes:

>char *p;
This certainly won't work until p is given something valid to point to. Try changing it to
Code:

char p[BUFSIZ];
>scanf("%[0-9 ]",&p);
Wow, non-portable, unsafe and undefined behavior all at the same time. Impressive. fgets would be better, but I can see why scanf was used. It would make more sense if the return value were checked. Since restricting valid input was the intention to begin with, it's silly to ignore a failure code.

I personally would have used fgets and sscanf myself:
Code:

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

void complain ( void )
{
fprintf ( stderr, "Invalid input\n" );
exit ( EXIT_FAILURE );
}

long sumofall ( const char *buffer )
{
long part;
long sum = 0;
int n; /* The number of characters converted by sscanf */

while ( sscanf ( buffer, "%ld%n", &part, &n ) == 1 ) {
sum += part;
buffer += n;
}

if ( *buffer != '\0' )
complain();

return sum;
}

int main ( void )
{
char buffer[BUFSIZ];

printf ( "Enter a list of numbers: " );
fflush ( stdout );

if ( fgets ( buffer, sizeof buffer, stdin ) != NULL ) {
char *newline = strchr ( buffer, '\n' );
if ( newline != NULL )
*newline = '\0';

printf ( "%ld\n", sumofall ( buffer ) );
}

return EXIT_SUCCESS;
}

• 09-05-2004
kermit
Quote:

Originally Posted by Prelude
Eew, what awful code.

;)

Quote:

>char *p;
This certainly won't work until p is given something valid to point to. Try changing it to
Code:

char p[BUFSIZ];

Or better..
Code:

#define BUFSIZE (some suitable number for *your* application)
...
char p[BUFSIZE];

• 09-05-2004
Prelude
>Or better..
I'd love to see your reasoning for why this is better based on the information given. :)
• 09-06-2004
kermit
Quote:

Originally Posted by Prelude
I'd love to see your reasoning for why this is better based on the information given.

I was not so much referring specifically to the OP's code - as scanf() was used and you could make your array as 'big' as BUFSIZ or some other larger number and it still could be overrun. I was stating my preference for not using BUFSIZ to size an array (in general, as opposed to this post specifically). I am not without reason to think the way I do.

First of all, how big is BUFSIZ? You can figure out how big it is on your computer, but how big is it on mine? (No board searches allowed ;)) The standard says that it must be minimum of 256 (section 7.19 I believe) but of course it can be bigger, or smaller, depending on the machine. There are certainly enough compilers out there that are not really up to date with ANSI standards. The point is that there is no consistency with the size of BUFSIZ. On your machine it might be 512. So when you code this:

Code:

char buf[BUFSIZ];
we know that if BUFSIZ does expand to 512, then you have done the same thing as this:

Code:

char buf[512];
Now compile it on a machine where BUFSIZ is 8192. Is it really necessary to declare an array with 8192 elements? Maybe it is, and maybe it is not. It depends on what is suitable for an application, but by using BUFSIZ you cannot be guaranteed that it will be a size that you think is suitable.

My main reason for not using BUFSIZ is that it is for use with the setbuf() function and really has nothing much at all to do with sizing arrays. Sure, its a handy little macro, but just because a macro exists does not mean it has to be used. Consider the following:

1) Write a program that will output the text, 'hello world' to the standard output 10 times.

Code:

#include <stdio.h>

int main(void)
{
int i;
for(i = 0; i < BUFSIZ; ++i) {
printf("This program sure prints a lot of lines\n");
}
return 0;
}

output:

test \$ ./big_loop | wc -l
8192
test \$

Oops! - that was not what was required. ;) You might be thinking, 'But in this case BUFSIZ has nothing to do with that program!' Exactly. It has as much to do with that loop as it has to do with anyone else using it to size an array. As far as I am concerned, using BUFSIZ to size an array is worse than using a 'magic number' to do the same thing. At least when the programmer decides on an arbitrary number (hopefully the number was chosen based on the requirements of the program) it will be the same number if it is compiled on a different machine. Not guaranteed at all when BUFSIZ is used.

The other reason I would tend to not use BUFSIZ is that it does not seem to me that it promotes good maintainable code. What happens if you decide later on that BUFSIZ is too small, and you want to change it? What if it is littered all throughout your code? Yes, replace-string works nicely on emacs, or, if the code is throughout several files, one might use sed, but is it not easier to just #define a thoughtful number and use that to set the size of a given array?

Of course it really comes down to personal preference. Using BUFSIZ to size an array is definitely idiomatic, but I am not convinced it is necessary, nor completely useful.

~/
• 09-06-2004
Prelude
That is a well thought out and lucid argument.

>how big is BUFSIZ?
Does it matter? If you need to read N characters but you don't know how many there will be then setting an arbitrary limit is silly to begin with. In the toy programs that are posted here, BUFSIZ is as good a value as any. In the real world, a buffer may well use BUFSIZ, but it will be a small part of a routine that grows another buffer dynamically so as to be robust by removing arbitrary limits on input.

If you use BUFSIZ as the buffer itself and not a helper for building the buffer then yes, you need to consider whether it is too big or too small. In that case the size might be important, application specific, and defining your own macro would be wise. But that doesn't change the fact that you're still forcing the user to conform to limits that you define, which is never good design sense.

>There are certainly enough compilers out there that are not really up to date with ANSI standards.
At which point nothing can be assuming about the language, so the argument is moot. If you don't trust the standard then there's nothing I can say.

>Oops! - that was not what was required.
I like how you used a macro that is defined as not having a set value (that is guaranteed to be at least 256) for a loop that requires a set number of iterations on all machines (that is considerably less than 256). :)

>it will be the same number if it is compiled on a different machine.
Will it? By your reasoning, implementations might have different limits for the size of an array. At that point a hard coded value may still not work right. ;)

>What if it is littered all throughout your code?
That's generally a problem with the code and not the macro.

>but I am not convinced it is necessary, nor completely useful.
I'm not convinced that you're looking at it the right way. You see the use of BUFSIZ as setting the size of an array and then using that array as the buffer. That's eminently reasonable because that's precisely how we use it here. :) But you have to remember that we strive for portable code. We often don't know what is best for an application in buffer sizing. And we don't have the time or the inclination (seeing as how we cater to beginners) to produce a proper buffering scheme using resizable arrays.

If I were to stop using BUFSIZ right now, the only thing that would change would be the array declaration, at which point I would replace BUFSIZ with 1024, which is my chosen arbitrary value that is not too big and not too small. Of course, then I would be hounded with questions about why I chose that value. I'm not interested in explaining myself on a regular basis, so I use BUFSIZ.
• 09-06-2004
kermit
Good points, duly noted.

~/
• 09-06-2004
linuxdude
plus different compilers have different max array elements. BUFSIZ will have to work on all ANSI compilers instead of some number that the programmer chooses.