String Extraction and Insertion Functions in C? - c

I need to write these two functions:
Precondition: hMy_string is the handle to a valid My_string object.
Postcondition: hMy_string will be the handle of a string object that contains
the next string from the file stream fp according to the following rules.
1) Leading whitespace will be ignored.
2) All characters (after the first non-whitespace character is obtained and included) will be added to the string until a stopping condition
is met. The capacity of the string will continue to grow as needed
until all characters are stored.
3) A stopping condition is met if we read a whitespace character after
we have read at least one non-whitespace character or if we reach
the end of the file.
Function will return SUCCESS if a non-empty string is read successfully.
and failure otherwise. Remember that the incoming string may aleady
contain some data and this function should replace the data but not
necessarily resize the array unless needed.
Status my_string_extraction(MY_STRING hMy_string, FILE* fp);
Precondition: hMy_string is the handle to a valid My_string object.
Postcondition: Writes the characters contained in the string object indicated by the handle hMy_string to the file stream fp.
Function will return SUCCESS if it successfully writes the string and
FAILURE otherwise.
Status my_string_insertion(MY_STRING hMy_string, FILE* fp);
However, I am getting a segmentation fault with my current code:
#include <stdio.h>
#include <stdlib.h>
#include "my_string.h"
Status my_string_extraction(MY_STRING hMy_string, FILE *fp)
{
string *pString = (string *) hMy_string;
int lws = 0;
int exit = 0;
int nws = 0;
int i;
int count = 0;
while(fp != NULL && exit == 0) {
if(pString->size >= pString->capacity) {
char *t_data = (char *)malloc(sizeof(char) * pString->capacity * 2);
if(t_data == NULL) {
return FAILURE;
}
for(i = 0; i < pString->size; i++) {
t_data[i] = pString->data[i];
}
free(pString->data);
pString->data = t_data;
pString->capacity *= 2;
if(getc(fp) == ' ' && lws == 0) {
lws++;
} else if(getc(fp) == ' ' && lws == 1) {
exit++;
} else if(getc(fp) == ' ' && nws > 0) {
exit++;
} else {
pString->data[count] = getc(fp);
count++;
pString->size++;
nws++;
}
fp++;
}
return SUCCESS;
}
Status my_string_insertion(MY_STRING hMy_string, FILE *fp)
{
int i;
string *pString = (string *) hMy_string;
for(i = 0; i < pString->size; i++) {
putc(pString->data[i], fp);
}
if(fp == NULL) {
return FAILURE;
}
return SUCCESS;
}

I am getting a segmentation fault with my current code
Why do you do this:
fp++; // incrementing pointer does not get you the next character in the file
When you try to get next character via getc(fp) that is enough to cause the crash . fp will be invalid pointer at that moment.
Also, I see no restrictions for crossing data boundary:
pString->data[count] = getc(fp);
count++; // count is not restricted from growing

Related

leaks in my C program i need to free all the leaks in my functions (except in the main , thats on the caller)

i'm writing a function (get_next_line) that returns a line read from a file descriptor, so i have the line stored in a char array that i return, now i need to process this line
so i read values into a buffer, whenever there are values read, the buffer should be processed, the newly added values should be joined with the result char array, if however, we encounter a newline, an extra step is required, i append the characters to the resulting array, until i reach the newline, which will be replaced by a null char, then the remaining values in the buffer should be stored in a static array that will append those values to the resulting string next time gnl is called.
the output of my function is correct my i need to deal with the leaks , i solved all of the leaks except the one related to the static char. btw im only allowed to use read() malloc() and free , all the other functions should be made by me (that explains the ft_ before each function in my code) here is my code :
valgrind results for the leaks
#include "get_next_line.h"
char * get_next_line(int fd) {
// // the reminder will contain the values after '\n' because the function should let
// you read the text file one line at a time. for example if the the buffer size is 5 and
// the first line is abc\nz we need to store the 'z' for the next line.
static char *reminder = "";
char buf[BUFFER_SIZE + 1];
int nbytes;
char * line = malloc(BUFFER_SIZE + 1);
if (!line || reminder == NULL) {
return NULL;
}
if (fd < 0 || fd > 999) {
free(line);
return NULL;
}
while ((nbytes = read(fd, buf, BUFFER_SIZE)) > 0) {
buf[nbytes] = '\0';
// ft_strjoin allocates and returns a new
// string, which is the result of the concatenation of ’s1’ and ’s2’.
reminder = ft_strjoin(reminder, buf);
//i modified strchr to returns a pointer to the character after '\n'
if (ft_strchr(reminder, '\n')) {
// each line from the txt file start from the index 0 to '\n'
line = ft_substr(reminder, 0, '\n');
reminder = ft_strchr(reminder, '\n');
return line;
}
}
if (ft_strcmp(reminder, "") == 0 || nbytes < 0 || reminder == NULL) {
free(line);
return NULL;
}
if ((!(ft_strchr(reminder, '\n')))) {
ptr = reminder;
reminder = NULL;
return ptr;
}
if (ft_strchr(reminder, '\n')) {
ptr = ft_substr(reminder, 0, '\n');
reminder = ft_strchr(reminder, '\n');
return ptr;
}
return NULL;
}
// here is my strjoin
char *ft_strjoin(char *s1, char *s2)
{
size_t size_s1;
size_t size_s2;
char *strjoin;
size_s1 = ft_strlen(s1);
size_s2 = ft_strlen(s2);
if (!(strjoin = malloc(size_s1 + size_s2 + 1)))
return (NULL);
ft_strcpy(strjoin, s1);
ft_strcat(strjoin, s2);
if(!(ft_strcmp(s1, "") == 0))
{
free(s1);
}
return (strjoin);
}

Chained strsep gives segmentation fault - C

I'm trying to create an array of array of strings to prepare them to be shown in a table.
So I have a function that returns a buffer string with the list of some scanned wifi access points, and I'm using strsep to split it by "\n" and then again by "\t".
The loop runs fine until it reaches the end and when the while argument ((line = strsep(&buf, "\n"))) is evaluated it gives a SEGFAULT.
Short Illustrative example asked per #Jabberwocky:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int
wap_scan_count_lines(char* wap_scan)
{
int line_amount = 0;
char *scan = wap_scan;
while(*scan)
{
if ('\n' == *scan){
line_amount++;
}
scan++;
}
return line_amount;
}
int main() {
char ***scan_result, *line=NULL, *item=NULL, *scan=NULL;
scan = strdup("bssid / frequency / signal level / flags / ssid\n"
"a8:6a:bb:e2:d6:ef 5785 -47 [WPA-PSK-CCMP+TKIP][WPA2-PSK-CCMP+TKIP][WPS][ESS] Fibertel WiFi114 5.8GHz");
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
int i = 0;
int item_len = sizeof (*scan_result);
while((line = strsep(&scan, "\n")) != NULL ) {
if(i==0){
i++;
continue;
}
char **scan_line = calloc(5, item_len);
int j = 0;
while ((item = strsep(&line, "\t")) != NULL) {
printf("%s\n", item);
scan_line[j++] = strdup(item);
}
scan_result[i++] = scan_line;
}
return 0;
}
The real function that gives me the problem:
char *** wifi_client_get_wap_list(int *len)
{
char ***scan_result;
char *buf, *buf_free, *cmd, *line, *item;
int ret, items_len;
cmd = strdup("SCAN");
ret = wpa_ctrl_command(cmd, NULL);
if (ret < 0) goto error;
cmd = strdup("SCAN_RESULTS");
ret = wpa_ctrl_command(cmd, &buf); //RETURNS A STRING ON BUF ALLOCATED BY STRDUP
if (ret < 0){
free(buf);
goto error;
}
*len = wap_scan_count_lines(buf); //NUMBER OF LINES IN THE SCAN RESULT
scan_result = calloc(*len, sizeof(**scan_result));
int i = 0, j;
buf_free = buf;
items_len = sizeof (*scan_result);
while ((line = strsep(&buf, "\n"))){ //THIS GIVES THE SEGFAULT AT THE END
// SKIP FIRST LINE WITH HEADERS
if (i==0){
i++;
continue;
}
//if (strcmp(line, "") == 0) {
// break;
//}
//EACH LINE HAS 5 VALUES (bssid, freq, level,flags,ssid)
char **scan_line = calloc(5, items_len);
j = 0;
printf("INNER STEPS:\n");
while((item = strsep(&line, "\t"))){
*(scan_line + j) = strdup(item);
printf("%d ", j);
j++;
}
*(scan_result + i) = scan_line;
printf("\nSTEP: %d\n", i);
i++;
}
free(buf_free);
free(cmd);
return scan_result;
error:
// #TODO: Handle error
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
} else if (ret < 0) {
printf("'%s' command failed.\n", cmd);
}
free(cmd);
return NULL;
}
Based on https://man7.org/linux/man-pages/man3/strsep.3.html the issue is that the loop will run one more time than you want it to, causing scan_result to overflow.
The relevant parts of the documentation are:
The strsep() function returns a pointer to the token, that is, it
returns the original value of *stringp.
and
If *stringp is NULL, the strsep() function returns NULL and does
nothing else. Otherwise, this function finds the first token in
the string *stringp, that is delimited by one of the bytes in the
string delim. This token is terminated by overwriting the
delimiter with a null byte ('\0'), and *stringp is updated to
point past the token. In case no delimiter was found, the token
is taken to be the entire string *stringp, and *stringp is made
NULL.
In wap_scan_count_lines you count the number of lines that are terminated with '\n'.
In the following 2 lines, you allocate the memory to hold the result based on the number of lines terminated with '\n'.
int wap_scan_size = wap_scan_count_lines(scan);
scan_result = malloc(wap_scan_size * sizeof(**scan_result));
However, the above quoted documentation for strsep() implies that in your simplified example the first wap_scan_size times strsep is called, at the end of the call the result will not be NULL and scan won't be set to NULL during the call. The next time through the call, scan will be set to NULL during the call but the result will not be NULL. This means that the body of the loop will be executed wap_scan_size + 1 times, causing a write past the end of scan_result.
There are at least two possible fixes, depending on whether you actually want to process any line at the end of the input that is not terminated by '\n'.
If you do need to process such lines, which seems more robust to me, particularly given that your simplified example ends with such a line, just allocate one extra entry in scan_result:
scan_result = malloc((wap_scan_size + 1) * sizeof(**scan_result));
If you are quite sure that you do not need to process such lines, but this seems incorrect to me, change:
while((line = strsep(&scan, "\n")) != NULL ) {
to
for(line = strsep(&scan, "\n"); scan != NULL; line = strsep(&scan, "\n") ) {

conflict of using strcpy , strcat in C?

In the following code I'm trying to load a text file of words character by character
then I'm trying to save each whole word in hash table (array of strings)
but it seems that strcpy saves a whole word not a single char and I don't know why. Am I misusing strcpy and strcat?
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <ctype.h>
# include <stdbool.h>
bool load(const char* dictionary);
#define LENGTH 45
int main (int argc, char* argv[])
{
char* dictionary = argv[1];
load(dictionary);
return 0;
}
bool load(const char* dictionary)
{
int index = 0, words = 0, kk = 0;
int lastl = 0, midl = 0;
char word[LENGTH + 1];
char *wholeword[1001];
FILE* dic = fopen(dictionary, "r");
if (dic == NULL)
{
printf("Could not open %s.\n", dictionary);
return false;
}
for (int c = fgetc(dic); c != EOF; c = fgetc(dic))
{
// allow only alphabetical characters and apostrophes
if (isalpha(c) || (c == '\'' && index > 0))
{
// append character to word
word[index] = c;
index++;
// ignore alphabetical strings too long to be words
if (index > LENGTH)
{
// consume remainder of alphabetical string
while ((c = fgetc(dic)) != EOF && isalpha(c));
// prepare for new word
index = 0;
}
}
// ignore words with numbers (like MS Word can)
else if (isdigit(c))
{
// consume remainder of alphanumeric string
while ((c = fgetc(dic)) != EOF && isalnum(c));
// prepare for new word
index = 0;
}
// we must have found a whole word
else if (index > 0)
{
// terminate current word
word[index] = '\0';
lastl = index - 1;
midl = (index - 1) % 3;
words++;
index = 0;
int hashi = (word[0] + word[lastl]) * (word[midl] + 17) % 1000;
wholeword[hashi] = (char*) malloc(sizeof(char) * (lastl + 2));
strcpy(wholeword[hashi], &word[0]); // ***
for (kk = 1; kk <= lastl + 1; kk++)
{
strcat(wholeword[words], &word[kk]);
}
}
}
fclose(dic);
return true;
}
Strcpy doesn't copy a single char, it copies all chars until the next null ('\0') byte. To copy a single char in your code try:
wholeword[hashi] = &word[0];
instead of:
strcpy(wholeword[hashi], &word[0]);
Yes you are misusing strcpy and strcat: these functions copy a whole source string to the destination array (at the end of an existing string there for strcat).
The following lines:
wholeword[hashi] = (char*) malloc(sizeof(char) * (lastl + 2));
strcpy(wholeword[hashi], &word[0]); // ***
for (kk = 1; kk <= lastl + 1; kk++)
{
strcat(wholeword[words], &word[kk]);
}
}
Can be replaced with a single call to
wholeword[hashi] = strdup(word);
strdup() allocates the memory, copies the argument string to it and returns the pointer. It is available on all Posix systems, if you do not have it, use these 2 lines:
wholeword[hashi] = malloc(lastl + 2);
strcpy(wholeword[hashi], word);
Notes:
you assume your hash to be perfect, without collisions. As currently coded, a collision causes the previous word to be removed from the dictionary and its corresponding memory to be lost.
the dictionary char *wholeword[1001]; is a local variable in the load function. It is uninitialized, so there is no way to know if an entry is a valid pointer to a word. It should be allocated, initialized to NULL and returned to the caller.

How to debug a Tree Summing and Runtime error?

I am looking at problem 112 from UVa Online Judge.
For a couple of weeks ago, I got some homeworks from my university and the thing is that, though other problems are accepted on the UVa, I cannot figure out what is going wrong with this problem. I've already run the input from Udebug website and there was no problem. I double-checked the result and now, I'm sick and tired of solving this issue.
Here are details about what has happened. First of all, I increase the BUFSIZE to 2^20 in order to avoid any memory overflow. The result? Failed. Second, I downsized the size of the element in the stack I made. The result? Failed. Lastly, I removed an eol character of the result just in case. The result? Failed.
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define BUFSIZE 16384
typedef struct node {
int element[BUFSIZE];
int size;
int current;
}Stack;//This is a stack I made
static Stack *stack;
static int level;//This is a level of a node in the whole tree
static int integer;//This is an integer that should be came out from the sum() function
bool initialize(void) {
if (stack == NULL)
stack = (Stack *)malloc(sizeof(Stack));
stack->size = BUFSIZE;
stack->current = 0;
return true;
}
bool push(int number) {
if (stack == NULL)
return false;
if ((stack->current + 1) > stack->size)
return false;
stack->element[stack->current] = number;
stack->current++;
return true;
}
int pop() {
if (stack->current <= 0)
return 0xFFFFFFFF;
stack->current--;
return stack->element[stack->current];
}
int sum() {
int result = 0;
int i;
if (stack == NULL)
return 0xFFFFFFFF;
if (stack->current == 0)
return 0xFFFFFFFF;
for (i = 0; i < stack->current; i++)
result += stack->element[i];
return result;
}//Sum all the values in the stack and return it.
void replace(char * o_string, char * s_string, char * r_string) {
char *buffer = (char *)calloc(BUFSIZE, sizeof(char));
char * ch;
if (!(ch = strstr(o_string, s_string)))
return;
strncpy(buffer, o_string, ch - o_string);
buffer[ch - o_string] = 0;
sprintf(buffer + (ch - o_string), "%s%s", r_string, ch + strlen(s_string));
o_string[0] = 0;
strcpy(o_string, buffer);
free(buffer);
return replace(o_string, s_string, r_string);
}//This is a function I found on Google. Memory usage optimization is not guaranteed.
int main(void) {
char *buffer;
char *line;
char *restOfTheString;
char *token;
bool checked = false, found = false;
int i = 0, j = 0, scannedInteger, result = 0, array[4096];
buffer = (char *)calloc(BUFSIZE, sizeof(char));
restOfTheString = (char *)calloc(BUFSIZE, sizeof(char));
line = (char *)calloc(BUFSIZE, sizeof(char));
memset(buffer, 0, BUFSIZE);
for (i = 0; i < 4096; i++) {
array[i] = -1;
}
level = 0;
integer = 0;
while (fgets(line, sizeof(line), stdin) != NULL) {//Get input line by line
if (line[0] != '\n') {
token = strtok(line, "\n");
if (strlen(line) >= 1) {
strcat(buffer, token);
}
}
}
replace(buffer, " ", "");
replace(buffer, "()()", "K");
strcpy(restOfTheString, buffer);
i = 0;
while (restOfTheString[i] != 0) {
if (level == 0 && !checked) {//If the level of the node is 0, then it is clearly the summed value I need to find out on the whole tree.
initialize();
sscanf(&restOfTheString[i], "%d%s", &integer, &restOfTheString[0]);
i = -1;
checked = true;
}
if (restOfTheString[i] == '(') {
checked = false;
level++;
}//If there is an openning bracket, then increase the level of the node.
else if (restOfTheString[i] == ')') {
if (restOfTheString[i - 1] != '(')
if (pop() == 0xFFFFFFFF)
return 0;
level--;
if (!found && level == 0) {
array[j] = 0;
j++;
free(stack);
stack = NULL;
}//If there is a closing bracket, then it's time to check whether the level of the node is 0. If the level of the node is 0, then we need to report the result to the 'array' which is an integer array and move on to the next input.
else if (found && level == 0) {
array[j] = 1;
j++;
free(stack);
stack = NULL;
found = false;
}
}
else if (restOfTheString[i] == '-' && !checked) {
if (sscanf(&restOfTheString[i], "%d%s", &scannedInteger, &restOfTheString[0]) == 2) {
if (push(scannedInteger) == false)
return 0;
i = -1;
}
}//If there is a minus character, then it's obvious that the next couple of characters are a negative integer and I need to scan it out of the whole input.
else if (restOfTheString[i] >= 48 && restOfTheString[i] <= 57 && !checked) {
if (sscanf(&restOfTheString[i], "%d%s", &scannedInteger, &restOfTheString[0]) == 2) {
if (push(scannedInteger) == false)
return 0;
i = -1;
}
}//If there is a numerous character, then it's obvious that the next couple of characters are a negative integer and I need to scan it out of the whole input.
else if (restOfTheString[i] == 'K') {
if ((result = sum()) == 0xFFFFFFFF)
return 0;
if (result == integer) {
found = true;
}
}//The 'K' character means the integer scanned prior to this iteration is a value in a leaf. So I need to call the sum() function in order to figure it out the result.
i++;
}
i = 0;
while (array[i] != -1) {
if (array[i] == 1)
printf("yes\n");
else if (array[i] == 0)
printf("no\n");
i++;
}
return 0;
}
Though it is clearly suspicious about the memory usage, I don't know how to track the stack on my system.
You use many questionable practices.
You free and re-allocate the stack from scratch. The stack has a fixed size in your case; allocate one at the beginning of main and free once at the end.
You set the index i to −1 as indicator, but keep on accessing restOfString[i] later. restOfString is an allocated string and writing to bytes before the actual data might corrupt the internal information that thze system keeps for allocated memory. This might lead to errors when freeing. In any case, it's undefined behaviour.
You read the input line-wise and concatenate everything into one huge string. You use strcat for this, which will get slower as your string grows. If you must load everything into a large buffer, consider using fread.
Your recursive replace method also does a lot of copying of temporarily allocated buffers.
This:
sscanf(&rest[i], "%d%s", &integer, &rest[0]);
looks fishy. You store the result in the string that you are reading, albeit at different indices. Result and source may overlap, which probably is undefined behaviour. In any case, it entails a lot of copying. Instead of using sscanf, you could read the integer with strtol, which gives you the position of the string after parsing the number. Continue scanning the old string at the resulting offset.
Your problems seem to be not in the core algorithm but with reading the input. Ihe assignment does not mention a maximum line length. This may be a sign that you shouldn't read the input in a line context.
You can use the scanf functions which don't know about line breaks. You can make use of the fact that unsuccessful scanning with data conversion, e.g. scanning an integer, resets the input stream.
Such a strategy would require only storage for the current token. You don't even need a stack if you use recursion. I doubt that the test cases in the online judge will break the stack limit, even if there they contain degenerate trees with a large depths.

Read one line of a text file in C on Unix — my read_line is broken?

I want to make a function that reads a line of your choice, from a given text file. Moving on to the function as parameters (int fd of the open, and int line_number)
It must do so using the language C and Unix system calls (read and / or open).
It should also read any spaces, and it must not have real limits (ie the line must be able to have a length of your choice).
The function I did is this:
char* read_line(int file, int numero_riga){
char myb[1];
if (numero_riga < 1) {
return NULL;
}
char* myb2 = malloc(sizeof(char)*100);
memset(myb2, 0, sizeof(char));
ssize_t n;
int i = 1;
while (i < numero_riga) {
if((n = read(file, myb, 1)) == -1){
perror("read fail");
exit(EXIT_FAILURE);
}
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
numero_riga++;
int j = 0;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return myb2;
}else{
myb2[j] = myb[0];
j++;
}
}
return myb2;
}
Until recently, I thought that this would work but it really has some problems.
Using message queues, the string read by the read_line is received as a void string ( "\0" ). I know the message queues are not the problem because trying to pass a normal string did not create the problem.
If possible I would like a fix with explanation of why I should correct it in a certain way. This is because if I do not understand my mistakes I risk repeating them in the future.
EDIT 1. Based upon the answers I decided to add some questions.
How do I end myb2? Can someone give me an example based on my code?
How do I know in advance the amount of characters that make up a line of txt to read?
EDIT 2. I don't know the number of char the line have so I don't know how many char to allocate; that's why I use *100.
Partial Analysis
You've got a memory leak at:
char* myb2 = (char*) malloc((sizeof(char*))*100);
memset(myb2, 0, sizeof(char));
if (numero_riga < 1) {
return NULL;
}
Check numero_riga before you allocate the memory.
The following loop is also dubious at best:
int i = 1;
while (i < numero_riga) {
ssize_t n = read(file, myb, 1);
if (strncmp(myb, "\n", 1) == 0) {
i++;
}else if (n == 0){
return NULL;
}
}
You don't check whether read() actually returned anything quick enough, and when you do check, you leak memory (again) and ignore anything that was read beforehand, and you don't detect errors (n < 0). When you do detect a newline, you simply add 1 to i. At no point do you save the character read in a buffer (such as myb2). All in all, that seem's pretty thoroughly broken…unless…unless you're trying to read the Nth line in the file from scratch, rather than the next line in the file, which is more usual.
What you need to be doing is:
scan N-1 lines, paying attention to EOF
while another byte is available
if it is newline, terminate the string and return it
otherwise, add it to the buffer, allocating space if there isn't room.
Implementation
I think I'd probably use a function get_ch() like this:
static inline int get_ch(int fd)
{
char c;
if (read(fd, &c, 1) == 1)
return (unsigned char)c;
return EOF;
}
Then in the main char *read_nth_line(int fd, int line_no) function you can do:
char *read_nth_line(int fd, int line_no)
{
if (line_no <= 0)
return NULL;
/* Skip preceding lines */
for (int i = 1; i < line_no; i++)
{
int c;
while ((c = get_ch(fd)) != '\n')
{
if (c == EOF)
return NULL;
}
}
/* Capture next line */
size_t max_len = 8;
size_t act_len = 0;
char *buffer = malloc(8);
int c;
while ((c = get_ch(fd)) != EOF && c != '\n')
{
if (act_len + 2 >= max_len)
{
size_t new_len = max_len * 2;
char *new_buf = realloc(buffer, new_len);
if (new_buf == 0)
{
free(buffer);
return NULL;
}
buffer = new_buf;
max_len = new_len;
}
buffer[act_len++] = c;
}
if (c == '\n')
buffer[act_len++] = c;
buffer[act_len] = '\0';
return buffer;
}
Test code added:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
extern char *read_nth_line(int fd, int line_no);
…code from main answer…
int main(void)
{
char *line;
while ((line = read_nth_line(0, 3)) != NULL)
{
printf("[[%s]]\n", line);
free(line);
}
return 0;
}
This reads every third line from standard input. It seems to work correctly. It would be a good idea to do more exhaustive checking of boundary conditions (short lines, etc) to make sure it doesn't abuse memory. (Testing lines of lengths 1 — newline only — up to 18 characters with valgrind shows it is OK. Random longer tests also seemed to be correct.)

Resources