Getting strange strings in C after reading getc from file - c

I am getting strange strings after the first iteration. I suspect it could be because of string termination, but I am not sure how to fix it. Or I might be using malloc the wrong way.
I am happy for any hints.
#include <stdio.h>
#include <memory.h>
#include <malloc.h>
#include <ctype.h>
#include "file_reader.h"
/**
* Opens a text file and reads the file. The text of the file is stored
* in memory in blocks of size blockSize. The linked list with the text is
* returned by the function. Each block should contain only complete words.
* If a word is split by the end of the block, the last letters should be
* moved into the next text block. Each text block must be NULL-terminated.
* If the reading of the file fails, the program should return a meaningful
* error message.
*/
int getFileSize(FILE* file) {
FILE* endOfFile = file;
fseek(endOfFile, 0, SEEK_END);
long int size = ftell(file);
fseek(file, 0, SEEK_SET);
return (int) size;
}
LinkedList* read_text_file(const char* filename, int blockSize) {
int globalByteCounter = 0;
LinkedList* list = LinkedList_create();
int blockByteCounter;
FILE* fp = fopen(filename, "r");
int fileSize = getFileSize(fp);
char* tokPointer = malloc(sizeof(getc(fp)));
char* block = malloc(sizeof strcat("",""));
//Loop for blocks in list
while (globalByteCounter <= fileSize) {
blockByteCounter = 0;
char* word = malloc(sizeof(blockSize));
//loop for each block
while(blockByteCounter<blockSize) {
char tok;
//Building a word
do {
strcat(word, tokPointer);
tok = (char) getc(fp);
tokPointer=&tok;
blockByteCounter++;
}while (isalpha(tok));
//Does this word still fit the block?
if (blockByteCounter + strlen(word) < blockSize) {
strcat(block, word);
//Setze Wort zurück und füge Sonderzeicehen an
word = strcpy(word,tokPointer);
} else {
strcpy(block,word);
}
}
globalByteCounter += blockByteCounter;
LinkedList_append(list, block);
free(word);
}
LinkedList_append(list,block);
fclose(fp);
free(block);
free(tokPointer);
return list;
}

There are multiple issues with the code. Let me tackle a few of them:
sizeof(getc(fp))
This is the same as applying sizeof on the return type of getc. In your case, what you are doing here is sizeof(int). That's not what you want.
Assuming that you have a text file, where the size of what you want to read is a number in ASCII, what you are looking for is the good old fscanf.
Similar here:
strcat("","")
but actually worse. strcat("a", "b") does not return "ab". It attempts to concatenate "b" onto "a" and returns the address of a, which is pretty bad because not only it doesn't do what you want, but also attempts to modify the string "a". You can't modify string literals.
blockByteCounter is not initialized.
And you got your hunch right:
char* word = malloc(sizeof(blockSize));
If you don't initialize word as an empty string, when you try to concatenate tokPointer onto it you'll run through a non-terminated string. Not only that, but tokPointer is also not initialized!
I'm also not sure why you are trying to use strcat to build a word. You don't need all those pointers. Once you know the required size of your buffer, you can 1) simply use fscanf to read one word; or 2) use fgetc with a good old simple counter i to put each letter into the buffer array, and then terminate it with 0 before printing.

Related

How do I read files from language C and save them as strings in memory, get the stored strings and cut them into a specific length? on linux LF format

I want to approach the string as an array, cut it to a specific length, and store it in a two-dimensional array. For example, I have 20 lines of text file. like this "input.txt"
www.google.com
www.naver.com
kbphonemall.com
kbplant.com
k-bplus.com
kbpointreestore.com
kbprint.com
kbprism.com
kbprivatebanking.com
kbpstore.com
kbr9rtudaf5ppy.com
kbrafting.com
kbraille.com
kbrainbank.com
kbrainbow.com
kbrainc.com
kbrainglocal.com
kbrandexpo.com
kbrandingschool.com
kbrandmall.com
and Then, I read this file and tried to crop it on each line using "\n as the key.
For example If you want to cut four lines at a time, you should cut it to "kbplant.com" first. And the truncated string looks like this.
www.google.com\nwww.naver.com\nkbphonemall.com\nkbplant.com\n
and It will then be stored in a pointer array. like this
char *cutting[n];
cutting[0] = "www.google.com\nwww.naver.com\nkbphonemall.com\nkbplant.com\n"
cutting[1] = "k-bplus.com\nkbpointreestore.com\nkbprint.com\nkbprism.com\n"
.... more
So far, that's the explanation of the functions I want to implement and I'll show you the code.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define IPATH "input.txt"
int main(int argc, char *argv[]) {
char *ListBuffer;
int ListSize;
FILE *InputFile = fopen(IPATH, "r");
fseek(InputFile, 0, SEEK_END);
ListSize = ftell(InputFile);
ListBuffer = malloc(ListSize);
memset(ListBuffer, 0, ListSize);
fseek(InputFile, 0, SEEK_SET);
fread(ListBuffer, ListSize, 1, InputFile);
int count = 0;
ListBuffer[ListSize] = '\0'; //add NULL word
for (int i = 0; i <= ListSize; i++) {
if (ListBuffer[i] == '\n') {
count++;
if (count == 4) {
printf("c%d\n", i);
count = 0;
}
}
if (ListBuffer[i] == 0) {
printf("c%d\n", i);
count = 0;
}
}
fclose(InputFile);
free(ListBuffer);
ListBuffer = NULL;
}
this is my code I have used various functions such as strcpy function, strtok function, memcpy function, etc., but it was difficult to implement the desired function. Is there a better way or algorithm?
If you need more explanation, I'll answer it quickly.
I would appreciate it if you could reply. Have a good day.
It is unclear what you are trying to achieve in the main loop, but there are more problems:
you must allocate one extra byte to set the null terminator at ListSize:
ListBuffer = malloc(ListSize + 1);
it is useless to set the array to 0 with memset: allocating with calloc(1, ListSize + 1) would be more efficient for this purpose, but since you read the contents into the array, clearing it first is useless.
fread might return a short count, for example in text mode on legacy systems, converting CR/LR sequences to newline bytes \n reduces the number of bytes read:
ListSize = fread(ListBuffer, 1, ListSize, InputFile);
ListBuffer[ListSize] = '\0'; // set the null terminator

Strange behaviour of printf with array when passing pointer to another function

To study for the exam we are trying to do some exercise from past exams.
In this exercise we get a header file and we have to create a function that read an input file and print onto the stdout only the parts of strings that do not contain digits.
(We have to pass the pointer of the string red to the main function).
We tried to do it with a an array but when printing the first word is empty or has strange characters. Instead doing a malloc allocation works fine.
What is also strange is that printing before everything an empty string will fix the code.
Therefore we don't understand why using an array of char the first word is not printed correctly, although it is saved in the buffer.
Including a printf before the while loop in the main function will reset the problem.
Using dynamic allocation (malloc) and not static allocation (array) will fix the print.
Iterating over the whole array and set all the memory to 0 does not fix the problem.
Therefore the pointer is correct as with printing an empty string it prints it correctly, but I really cannot understand what cause the issue.
Question are:
How it is possible that printing an empty string the print is correct?
Array is allocated on the stack therefore it is deallocated when the program exit the scope, why is only the first broken and not all the words?
#include "word_reader.h"
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
const char * read_next_word(FILE * f) {
char buffer[WORD_MAX_LEN];
char * word = buffer;
for (int i = 0; i < WORD_MAX_LEN; ++i)
buffer[i] = 0;
//char * buffer = malloc(sizeof(char) * WORD_MAX_LEN);
int found = 0;
int c = 0;
int i = 0;
while (!found && c != EOF) {
while ((c = fgetc(f)) != EOF && isalpha(c)) {
found = 1;
buffer[i] = c;
++i;
}
buffer[i] = '\0';
}
if (found) {
return word;
//return buffer; // when use malloc
}
return 0;
}
int main(int argc, char * argv[]) {
FILE * f = fopen(argv[1], "r");
if(!f) {
perror(argv[1]);
return EXIT_FAILURE;
}
const char * word = 0;
//printf(""); // adding this line fix the problem
while ((word = read_next_word(f))) {
printf("%s\n", word);
}
fclose(f);
return 0;
}
the header file contain only the read_next_word declaration and define WORD_MAX_LEN to 1024. (Also include
the file to read (a simple .txt file)
ciao234 44242 toro
12Tiz23 where333
WEvo23
expected result:
ciao
toro
Tiz
where
WEvo
actual result
�rǫs+)co�0�*�E�L�mзx�<�/��d�c�q
toro
Tiz
where
WEvo
the first line is always some ascii characters or an empty line.

How should I fix this interesting getdelim / getline (dynamic memory allocation) bug?

I have this C assignment I am a bit struggling at this specific point. I have some background in C, but pointers and dynamic memory management still elude me very much.
The assignment asks us to write a program which would simulate the behaviour of the "uniq" command / filter in UNIX.
But the problem I am having is with the C library functions getline or getdelim (we need to use those functions according to the implementation specifications).
According to the specification, the user input might contain arbitrary amount of lines and each line might be of arbitrary length (unknown at compile-time).
The problem is, the following line for the while-loop
while (cap = getdelim(stream.linesArray, size, '\n', stdin))
compiles and "works" somehow when I leave it like that. What I mean by this is that, when I execute the program, I enter arbitrary amount of lines of arbitrary length per each line and the program does not crash - but it keeps looping unless I stop the program execution (whether the lines are correctly stored in " char **linesArray; " are a different story I am not sure about.
I would like to be able to do is something like
while ((cap = getdelim(stream.linesArray, size, '\n', stdin)) && (cap != -1))
so that when getdelim does not read any characters at some line (besides EOF or \n) - aka the very first time when user enters an empty line -, the program would stop taking more lines from stdin.
(and then print the lines that were stored in stream.linesArray by getdelim).
The problem is, when I execute the program if I make the change I mentioned above, the program gives me "Segmentation Fault" and frankly I don't know why and how should I fix this (I have tried to do something about it so many times to no avail).
For reference:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/getdelim.html
https://en.cppreference.com/w/c/experimental/dynamic/getline
http://man7.org/linux/man-pages/man3/getline.3.html
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFAULT_SIZE 20
typedef unsigned long long int ull_int;
typedef struct uniqStream
{
char **linesArray;
ull_int lineIndex;
} uniq;
int main()
{
uniq stream = { malloc(DEFAULT_SIZE * sizeof(char)), 0 };
ull_int cap, i = 0;
size_t *size = 0;
while ((cap = getdelim(stream.linesArray, size, '\n', stdin))) //&& (cap != -1))
{
stream.lineIndex = i;
//if (cap == -1) { break; }
//print("%s", stream.linesArray[i]);
++i;
if (i == sizeof(stream.linesArray))
{
stream.linesArray = realloc(stream.linesArray, (2 * sizeof(stream.linesArray)));
}
}
ull_int j;
for (j = 0; j < i; ++j)
{
printf("%s\n", stream.linesArray[j]);
}
free(stream.linesArray);
return 0;
}
Ok, so the intent is clear - use getdelim to store the lines inside an array. getline itself uses dynamic allocation. The manual is quite clear about it:
getline() reads an entire line from stream, storing the address of the
buffer containing the text into *lineptr. The buffer is
null-terminated and includes the newline character, if one was found.
The getline() "stores the address of the buffer into *lineptr". So lineptr has to be a valid pointer to a char * variable (read that twice).
*lineptr and *n will be updated
to reflect the buffer address and allocated size respectively.
Also n needs to be a valid(!) pointer to a size_t variable, so the function can update it.
Also note that the lineptr buffer:
This buffer should be freed by the user program even if getline() failed.
So what do we do? We need to have an array of pointers to an array of strings. Because I don't like becoming a three star programmer, I use structs. I somewhat modified your code a bit, added some checks. You have the excuse me, I don't like typedefs, so I don't use them. Renamed the uniq to struct lines_s:
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
struct line_s {
char *line;
size_t len;
};
struct lines_s {
struct line_s *lines;
size_t cnt;
};
int main() {
struct lines_s lines = { NULL, 0 };
// loop breaks on error of feof(stdin)
while (1) {
char *line = NULL;
size_t size = 0;
// we pass a pointer to a `char*` variable
// and a pointer to `size_t` variable
// `getdelim` will update the variables inside it
// the initial values are NULL and 0
ssize_t ret = getdelim(&line, &size, '\n', stdin);
if (ret < 0) {
// check for EOF
if (feof(stdin)) {
// EOF found - break
break;
}
fprintf(stderr, "getdelim error %zd!\n", ret);
abort();
}
// new line was read - add it to out container "lines"
// always handle realloc separately
void *ptr = realloc(lines.lines, sizeof(*lines.lines) * (lines.cnt + 1));
if (ptr == NULL) {
// note that lines.lines is still a valid pointer here
fprintf(stderr, "Out of memory\n");
abort();
}
lines.lines = ptr;
lines.lines[lines.cnt].line = line;
lines.lines[lines.cnt].len = size;
lines.cnt += 1;
// break if the line is "stop"
if (strcmp("stop\n", lines.lines[lines.cnt - 1].line) == 0) {
break;
}
}
// iterate over lines
for (size_t i = 0; i < lines.cnt; ++i) {
// note that the line has a newline in it
// so no additional is needed in this printf
printf("line %zu is %s", i, lines.lines[i].line);
}
// getdelim returns dynamically allocated strings
// we need to free them
for (size_t i = 0; i < lines.cnt; ++i) {
free(lines.lines[i].line);
}
free(lines.lines);
}
For such input:
line1 line1
line2 line2
stop
will output:
line 0 is line1 line1
line 1 is line2 line2
line 2 is stop
Tested on onlinegdb.
Notes:
if (i == sizeof(stream.linesArray)) sizeof does not magically store the size of an array. sizeof(stream.linesArray) is just sizeof(char**) is just a sizeof of a pointer. It's usually 4 or 8 bytes, depending if on the 32bit or 64bit architecture.
uniq stream = { malloc(DEFAULT_SIZE * sizeof(char)), - stream.linesArray is a char** variable. So if you want to have an array of pointers to char, you should allocate the memory for pointers malloc(DEFAULT_SIZE * sizeof(char*)).
typedef unsigned long long int ull_int; The size_t type if the type to represent array size or sizeof(variable). The ssize_t is sometimes used in posix api to return the size and an error status. Use those variables, no need to type unsigned long long.
ull_int cap cap = getdelim - cap is unsigned, it will never be cap != 1.

Printf() prints string arguments out of order

I have some C-code that reads in a text file line by line, hashes the strings in each line, and keeps a running count of the string with the biggest hash values.
It seems to be doing the right thing but when I issue the print statement:
printf("Found Bigger Hash:%s\tSize:%d\n", textFile.biggestHash, textFile.maxASCIIHash);
my print returns this in the output:
Preprocessing: dict1
Found BiSize:110h:a
Found BiSize:857h:aardvark
Found BiSize:861h:aardwolf
Found BiSize:937h:abandoned
Found BiSize:951h:abandoner
Found BiSize:1172:abandonment
Found BiSize:1283:abbreviation
Found BiSize:1364:abiogenetical
Found BiSize:1593:abiogenetically
Found BiSize:1716:absentmindedness
Found BiSize:1726:acanthopterygian
Found BiSize:1826:accommodativeness
Found BiSize:1932:adenocarcinomatous
Found BiSize:2162:adrenocorticotrophic
Found BiSize:2173:chemoautotrophically
Found BiSize:2224:counterrevolutionary
Found BiSize:2228:counterrevolutionist
Found BiSize:2258:dendrochronologically
Found BiSize:2440:electroencephalographic
Found BiSize:4893:pneumonoultramicroscopicsilicovolcanoconiosis
Biggest Size:46umonoultTotal Words:71885covolcanoconiosis
So tt seems I'm misusing printf(). Below is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORD_LENGTH 100 // Max number of characters per word
// data1 struct carries information about the dictionary file; preprocess() initializes it
struct data1
{
int numRows;
int maxWordSize;
char* biggestWord;
int maxASCIIHash;
char* biggestHash;
};
int asciiHash(char* wordToHash);
struct data1 preprocess(char* fileName);
int main(int argc, char* argv[]){
//Diagnostics Purposes; Not used for algorithm
printf("Preprocessing: %s\n",argv[1]);
struct data1 file = preprocess(argv[1]);
printf("Biggest Word:%s\t Size:%d\tTotal Words:%d\n", file.biggestWord, file.maxWordSize, file.numRows);
//printf("Biggest hashed word (by ASCII sum):%s\tSize: %d\n", file.biggestHash, file.maxASCIIHash);
//printf("**%s**", file.biggestHash);
return 0;
}
int asciiHash(char* word)
{
int runningSum = 0;
int i;
for(i=0; i<strlen(word); i++)
{
runningSum += *(word+i);
}
return runningSum;
}
struct data1 preprocess(char* fName)
{
static struct data1 textFile = {.numRows = 0, .maxWordSize = 0, .maxASCIIHash = 0};
textFile.biggestWord = (char*) malloc(WORD_LENGTH*sizeof(char));
textFile.biggestHash = (char*) malloc(WORD_LENGTH*sizeof(char));
char* str = (char*) malloc(WORD_LENGTH*sizeof(char));
FILE* fp = fopen(fName, "r");
while( strtok(fgets(str, WORD_LENGTH, fp), "\n") != NULL)
{
// If found a larger hash
int hashed = asciiHash(str);
if(hashed > textFile.maxASCIIHash)
{
textFile.maxASCIIHash = hashed; // Update max hash size found
strcpy(textFile.biggestHash, str); // Update biggest hash string
printf("Found Bigger Hash:%s\tSize:%d\n", textFile.biggestHash, textFile.maxASCIIHash);
}
// If found a larger word
if( strlen(str) > textFile.maxWordSize)
{
textFile.maxWordSize = strlen(str); // Update biggest word size
strcpy(textFile.biggestWord, str); // Update biggest word
}
textFile.numRows++;
}
fclose(fp);
free(str);
return textFile;
}
You forget to remove the \r after reading. This is in your input because (1) your source file comes from a Windows machine (or at least one which uses \r\n line endings), and (2) you use the fopen mode "r", which does not translate line endings on your OS (again, presumably Windows).
This results in the weird output as follows:
Found Bigger Hash:text\r\tSize:123
– see the position of the \r? So what happens when outputting this string, you get at first
Found Bigger Hash:text
and then the cursor gets repositioned to the start of the line by \r. Next, a tab is output – not by printing spaces but merely moving the cursor to the 8thth position:
1234567↓
Found Bigger Hash:text
and the rest of the string is printed over the one already shown:
Found BiSize:123h:text
Possible solutions:
Open your file in "rt" "text" mode, and/or
Check for, and remove, the \r code as well as \n.
I'd go for both. strchr is pretty cheap and will make your code a bit more foolproof.
(Also, please simplify your fgets line by splitting it up into several distinct operations.)
Your statement
while( strtok(fgets(str, WORD_LENGTH, fp), "\n") != NULL)
takes no account of the return value from fgets() or the way strtok() works.
The way to do this is something like
char *fptr, *sptr;
while ((fptr = fgets(str, WORD_LENGTH, fp)) != NULL) {
sptr = strtok(fptr, "\n");
while (sptr != NULL) {
printf ("%s,", sptr);
sptr = strtok (NULL, "\n");
}
printf("\n");
}
Note than after the first call to strtok(), subsequent calls on the same sequence must pass the parameter NULL.

from static array assignment to array from file

I have this piece of code outside the main function
mystr * arrstr[] = {
"rec",
"cent",
"ece",
"ce",
"recent",
"nt",
};
I modified it so that it can read the values from a text file. for this purpose i modified this working code to read line from file into array named string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
int i=0,j;
char* string[100];
char line[100];
FILE *file;
file = fopen("patt", "r");
while(fgets(line, sizeof(line), file)!=NULL) {
printf("%s", line);
string[i] = (char*)malloc(strlen(line));
strcpy(string[i], line);
i++;
}
fclose(file);
return 0;
}
so the final code is now something like this.
..
..
char *getpatterns(const char *filename) {
int i=0;
char* string[100];
char line[100];
FILE *file;
file = fopen(filename, "r");
while(fgets(line, sizeof(line), file)!=NULL) {
//printf("%s", line);
string[i] = (char*)malloc(strlen(line));
strcpy(string[i], line);
i++;
}
fclose(file);
return(string);
}
mystr * arrstr[] = getpatterns("patt");/*{
"rec",
"cent",
"ece",
"ce",
"recent",
"nt",
};*/
..
..
But i get errors like this.
example1.c: In function ‘getpatterns’:
example1.c:43:2: warning: return from incompatible pointer type [enabled by default]
example1.c:43:2: warning: function returns address of local variable [enabled by default]
example1.c: At top level:
example1.c:45:1: error: invalid initializer
make: *** [example1.o] Error 1
Here line 45 is this line
mystr * arrstr[] = getpatterns("patt");/*{
Please suggest corrective action.
The first warnings are that you are trying to return a char ** as a char * (which is not a good idea), and that you are returning a local variable which is deallocated when the function returns (also not a good idea). The last is telling you that you can't use function calls in initializers of global variables in C (you can do some of that in C++, though I'm not convinced you can do this one).
Fixing it will take some rethinking. You need the function to return allocated memory, or you need to pass the memory to the function. And you'll have to change the type of the global variable. And you'll need to know how many entries there are in the array, somehow.
mystr **arrstr = 0; // Either
mystr *arrstr[100]; // Or
On the whole, I'd probably go with memory allocation and the 'either' declaration:
mystr **arrstr = 0;
char **getpatterns(const char *file)
{
char **array = 0;
...code similar to yours that allocates entries in the array...
...include space for a null pointer to mark the end of the list of strings...
return(array);
}
int main(void)
{
arrstr = getpatterns("patt");
...
}
(Another 'cheat' mechanism would use static char *string[100]; in getpatterns(); you still have to fix the return type and the type of the global variable.)
I tried these but, errors were not resolved: ...
It's impossible to tell exactly what was wrong without your code. However, the code below works for me. The source code was in a file gp.c; the source code prints itself, and releases the memory. Checked under valgrind with a clean bill of health.
Note that your original code did not allocate enough space for the strings it was copying (because you retained the newline read by fgets() — but you were at least using fgets() and not gets(), which is very important). This code uses memmove() — it could use memcpy() instead since there's guaranteed to be no overlap, but memmove() always works and memcpy() doesn't necessarily work when the source data overlaps the target data. It knows how long the string is, so the copy function doesn't need to test for whether the character being copied is a NUL '\0'. The code carefully ensures that there's a null pointer at the end of the list of pointers; that's how you know when you've reached the end of the list of strings. The code also works when gp.c is an empty file.
The algorithm using three items num_xxx, max_xxx, and xxx is a typical way to handle incremental allocation. It typically over-allocates slightly; if you're concerned about the space, you could use strings = realloc(strings, (num_strings+1) * sizeof(*strings)); max_strings = num_strings + 1; at the end of the loop to release the extra space. The + 1 is to allow for the null pointer. By roughly doubling the size allocated each time you allocate, you avoid quadratic behaviour compared with incrementing by one each time.
Notice too that the code carefully avoids losing the allocated space if the realloc() fails. You should 'never' use space = realloc(space, new_size); to avoid losing your pointer. The code carefully avoids dereferencing null pointers, and simply stops reading when there is a memory shortage.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
extern char **getpatterns(const char *filename);
char **getpatterns(const char *filename)
{
size_t num_strings = 0;
size_t max_strings = 0;
char **strings = 0;
FILE *file = fopen(filename, "r");
if (file != 0)
{
char line[4096];
while (fgets(line, sizeof(line), file) != NULL)
{
if (max_strings == 0 || num_strings >= max_strings - 1)
{
size_t new_num = max_strings * 2 + 2;
char **new_space = realloc(strings, new_num * sizeof(*new_space));
if (new_space == 0)
break;
strings = new_space;
max_strings = new_num;
}
size_t len = strlen(line); /* Includes '\n' at end */
strings[num_strings] = (char*)malloc(len);
memmove(strings[num_strings], line, len - 1);
strings[num_strings][len] = '\0';
strings[++num_strings] = 0; /* Null terminate list of strings */
}
fclose(file);
}
return(strings);
}
int main(void)
{
char **data = getpatterns("gp.c");
char **argp = data;
if (argp != 0)
{
/* Print data */
while (*argp != 0)
puts(*argp++);
/* Free space */
argp = data;
while (*argp != 0)
free(*argp++);
free(data);
}
return(0);
}

Resources