stack smashing

F

frank

jaysome said:
#include <stdio.h>
int main(void)
{
printf("sizeof(int)is %zu\n", sizeof(int));
return 0;
}

This is the output I get with VC++ 6.0:

sizeof(int)is zu

That's because the "%zu" conversion specifier is new in C99, and VC++
6.0, like most of the dozen or so compilers I use, are not
C99-compliant. I think it will always be this way. YMMV.

My mileage didn't vary, which is why I stopped using VC++6. It's stuck
in the eighties like the mullet, preppie clothes, and cocaine.
So rather than have to deal with portability issues, I simply write:

#include <stdio.h>
int main(void)
{
printf("sizeof(int) is %d\n", (int)sizeof(int));
return 0;
}

When I know a number isn't going to be bigger than a hundred, I don't
care enough sometimes to add a cast.
 
F

frank

Jens said:
Nearly - but since it's supposed to return an array of strings
it has to be

char ** getDir( char * pathName);

Thanks, Jens, I won't forget to add the const, but I did tonight. I
think I've got a pretty good template to move forward. I see the
analogy between reading a text file with standard c and reading a
directory with posix extensions. I think both tasks are suited to
resizable 2-d arrays.

So this is what I have (thanks, Richard):

dan@dan-desktop:~/source/unleashed/ch11$ gcc -Wall -Wextra -c -o
string2.o strarr2.c
dan@dan-desktop:~/source/unleashed/ch11$ gcc -std=c99 -Wall -Wextra
string2.o t2.c -o out
dan@dan-desktop:~/source/unleashed/ch11$ ./out strarr2.c


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

#include "strarr.h"

void FreeStrArray(char **Array, size_t NumFiles)
{
size_t index;

if(Array != NULL)
{
for(index = 0; index < NumFiles; index++)
{
if(Array[index] != NULL)
{
free(Array[index]);
}
}
free(Array);
}
}

char **AllocStrArray(size_t NumFiles, size_t Width)
{
char **Array = NULL;
size_t index;
int Success = 1;

/* allocating 0 bytes is not a great idea, and
* represents a logic error.
*/
assert(NumFiles > 0);
assert(Width > 0);

/* Just in case the zero allocation is NOT caught
* in testing, we'll check for it here.
*/
if(NumFiles > 0 && Width > 0)
{
Array = malloc(NumFiles * sizeof *Array);
if(Array != NULL)
{
for(index = 0; index < NumFiles; index++)
{
Array[index] = malloc(Width * sizeof *Array[index]);
if(NULL == Array[index])
{
Success = 0;
}
else
{
/* Making this into an empty string is a quick
* op which will almost invariably be The Right
* Thing and can never be The Wrong Thing, so
* we might as well do it.
*/
Array[index][0] = '\0';
}
}
/* If any inner allocation failed,
* we should clean up.
*/
if(1 != Success)
{
FreeStrArray(Array, NumFiles);
Array = NULL;
}
}
}

return Array;
}

int ResizeOneString(char **Array,
size_t index,
size_t NewSize)
{
char *p;
int Success = 1;

assert(Array != NULL);

p = realloc(Array[index], NewSize);
if(p != NULL)
{
Array[index] = p;
}
else
{
Success = 0;
}

return Success;
}

int AddFilesToStrArray(char ***ArrayPtr,
size_t OldNumFiles,
int NumFilesToAdd,
size_t InitWidth)
{
char **p;
int Success = 1;
int index;
int OldFiles;

OldFiles = (int)OldNumFiles;
if(NumFilesToAdd < 0)
{
for(index = OldFiles - 1;
index >= OldFiles + NumFilesToAdd;
index--)
{
free((*ArrayPtr)[index]);
}
}

p = realloc(*ArrayPtr,
(OldFiles + NumFilesToAdd) *
sizeof(**ArrayPtr));

if(p != NULL)
{
*ArrayPtr = p;

for(index = OldFiles;
Success && index < OldFiles + NumFilesToAdd;
index++)
{
(*ArrayPtr)[index] = malloc(InitWidth);
if((*ArrayPtr)[index] != NULL)
{
(*ArrayPtr)[index][0] = '\0';
}
else
{
Success = 0;
}
}
}
else
{
Success = 0;
}
return Success;
}

int ConsolidateStrArray(char **ArrayPtr,
size_t NumFiles)
{
size_t index;
size_t Len;
int NumFailures = 0;

for(index = 0; index < NumFiles; index++)
{
/* If the library has been correctly used, no
* index pointer will ever be NULL, so we should
* assert that this is the case.
*/
assert(ArrayPtr[index] != NULL);
Len = 1 + strlen(ArrayPtr[index]);
if(0 == ResizeOneString(ArrayPtr, index, Len))
{
++NumFailures;
}
}
return NumFailures;
}

/* end of strarr.c */
/*
gcc -Wall -Wextra -c -o string2.o strarr2.c */
dan@dan-desktop:~/source/unleashed/ch11$ ./out t2.c
#include <stdio.h>
#include <string.h>

#include "strarr2.h"

#define DEFAULT_LINE_LEN 64
#define LINES_PER_ALLOC 16
#define ERR_FILES_NOT_ADDED 1
#define ERR_STRING_NOT_RESIZED 2
#define ERR_PATH_OPEN_FAILED 3
#define ERR_ALLOC_FAILED 4

int ReadFile(char *Filename,
char ***Array,
int *NumFiles)
{
char Buffer[DEFAULT_LINE_LEN] = {0};
char *NewLine = NULL;
FILE *fp;
int Error = 0;
int index = 0;
size_t NumBlocks;

*NumFiles = 0;

*Array = AllocStrArray(LINES_PER_ALLOC,
DEFAULT_LINE_LEN);
if(NULL != *Array)
{
fp = fopen(Filename, "r");
if(fp != NULL)
{
*NumFiles = LINES_PER_ALLOC;
NumBlocks = 1;

/* fgets will give us no more than sizeof Buffer
* bytes, including zero terminator and newline
* if one is present within that number of bytes.
* Therefore we need to cater for longer lines.
* To do this, we call fgets again (and again
* and again) until we encounter a newline.
*/
while(0 == Error &&
NULL != fgets(Buffer, sizeof Buffer, fp))
{
NewLine = strchr(Buffer, '\n');
if(NewLine != NULL)
{
*NewLine = '\0';
}
/* This strcat relies on the AllocStrArray()
* function initialising indexs to empty strings.
*/
strcat((*Array)[index], Buffer);
if(NewLine != NULL)
{
/* There was a newline, so the
* next line is a new one.
*/
NumBlocks = 1;
++index;
if(index >= *NumFiles)
{
/* Add another LINES_PER_ALLOC lines.
* If it didn't work, give up.
*/
if(0 == AddFilesToStrArray(Array,
*NumFiles,
LINES_PER_ALLOC,
DEFAULT_LINE_LEN))
{
Error = ERR_FILES_NOT_ADDED;
}
else
{
*NumFiles += LINES_PER_ALLOC;
}
}
}
else
{
++NumBlocks;
/* Make room for some more data on this line */
if(0 ==
ResizeOneString(*Array,
index,
NumBlocks * DEFAULT_LINE_LEN))
{
Error = ERR_STRING_NOT_RESIZED;
}
}
}
fclose(fp);
if(0 == Error && *NumFiles > index)
{
if(0 == AddFilesToStrArray(Array,
*NumFiles,
index - *NumFiles,
0))
{
Error = ERR_ALLOC_FAILED;
}
*NumFiles = index;
}
}
else
{
Error = ERR_PATH_OPEN_FAILED; /* Can't open file */
}
}
else
{
Error = ERR_ALLOC_FAILED; /* Can't allocate memory */
}
if(Error != 0)
{
/* If the original allocation failed,
* *Array will be NULL. FreeStrArray()
* correctly handles this possibility.
*/
FreeStrArray(*Array, *NumFiles);
*NumFiles = 0;
}
else
{
ConsolidateStrArray(*Array, *NumFiles);
}

return Error;
}

int main(int argc, char **argv)
{
char **array = NULL;

int numFiles;
int index;
int error;

if(argc > 1)
{
error = ReadFile(argv[1], &array, &numFiles);
switch(error)
{
case 0:
for(index = 0; index < numFiles; index++)
{
printf("%s\n", array[index]);
}

FreeStrArray(array, numFiles);
break;
case ERR_STRING_NOT_RESIZED:
case ERR_ALLOC_FAILED:
case ERR_FILES_NOT_ADDED:
puts("Insufficient memory.");
break;
case ERR_PATH_OPEN_FAILED:
printf("Couldn't open %s for reading\n", argv[1]);
break;
default:
printf("Unknown error! Code %d.\n", error);
break;
}
}
else
{
puts("Please specify the text file name.");
}

return 0;
}
/* end of c11_018.c */

/*
gcc -std=c99 -Wall -Wextra string2.o t2.c -o out */
dan@dan-desktop:~/source/unleashed/ch11$

My questions now focus on main. Somehow, I've got to take this line:
error = ReadFile(argv[1], &array, &numFiles);
, and turn it into:
char ** getDir( const char * pathName);

Any constructive comments gladly received. Cheers,
 
D

David Thompson

(Topic change.) This "int vs. size_t" question makes me remember what I
don't really like about the printf() family:

- The return value signals the number of characters transmitted (if no
error occurred). While strlen() returns a size_t, printf() and co.
return an int.
The return value needs to allow negative for error. Like some other
stdio routines and many Unix syscalls, this practice of 'inband' error
indication isn't aesthetically beautiful, but it worked and at this
point we're basically stuck with it.
- Same for %n.
Pointer (both *scanf and *printf), so once set unsafe to change.
- Same for the "*" field width and precision.
(For *printf only) varargs, thus less convenient to use something that
might be wider than u/int.

Remember that much of what is now the standard library was first
implemented while the type system was still in some flux, and there
was no point thereafter when there was agreement on a flag-day change.
It would be nicer if dmr&co had been prescient, but they had enough
trouble getting anything to work at all, and AIUI no idea C would
become as widespread and persistent as it did.

C89 did make certainly most and I think all value arguments, which can
be (automatically) fixed by the newly-added prototypes, size_t.
(C99 7.19.6.1 The fprintf function, p15:

----v----
Environmental limits

The number of characters that can be produced by any single conversion
shall be at least 4095.
----^----

Does this mean one can't portably pass a string to a single %s if
strlen() returns at least 4096 for that string?)
AIUI not absolutely 100% guaranteed portable, no. FWIW *f were
originally intended mostly to be human read or entered, or at least
editted, and single chunks of data larger than some tens of chars, or
at least hundreds, are usually unsuitable for that. IME when I need
(in C) to do larger chunks they are handled separately and it's no
real trouble to use fwrite().
I have the (very superficial) impression that unsigned integers are
historically very under-used in favor of signed integers. For example,
the (not standard C) BSD socket interfaces historically took a lot of
"size parameters" (obvious candidates for the sizeof operator) as int's:

<snip long rant ending mostly in socklen_t> (actually int or int*)

Yeah, by the time sockets was done, there was enough experience they
could have got this one right. Especially since they worked hard to
support extendable network types, almost all of which have turned out
to be useless. OTOH if addresses (or options) ever really need to
exceed 32K I don't want to be there to see it, so in practice it
doesn't actually cause a problem, just looks a bit ugly.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,754
Messages
2,569,521
Members
44,995
Latest member
PinupduzSap

Latest Threads

Top