I'm having some issues with this section of the book about pointers and memory management.
My program crashes after the first line of input and I can't understand where is the issue.
I tried to write and execute the code that is shown on the book - should be at page 120, the section around pointers to functions. Basically I give some input lines and they are sorted, either numerically (if I specify it with -n) or lexicographically. I don't have issue with the understanding of the pointers to function and how they work (maybe a bit), but with some unexpected crash that occurs after my first line of input. Basically when I execute the code and type something, it stops for a while and then terminates.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXLEN 1000
#define MAXLINES 5000
char *lineptr[MAXLINES];
int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void myqsort(void *lineptr[], int left, int right,
int (*comp)(void *, void *));
int numcmp(char *, char *);
/* sort input lines */
int main(int argc, char *argv[])
{
int nlines; /* number of input lines read */
int numeric = 0; /* 1 if numeric sort */
if (argc > 1 && !strcmp(argv[1], "-n"))
numeric = 1;
if ((nlines = readlines(lineptr, MAXLINES)) > 0)
{
if (numeric)
myqsort((void **) lineptr, 0, nlines - 1,
(int (*)(void *, void *))(numcmp));
else
myqsort((void **) lineptr, 0, nlines - 1,
(int (*)(void *, void *))(strcmp));
writelines(lineptr, nlines);
return 0;
}
else {
printf("input too big to sort\n");
return 1;
}
}
/* get the input line */
int getline(char *line, int max)
{
int c, i;
for (i = 0; i < max - 1 && (c = getchar()) != EOF && c != '\n'; i )
line[i] = c;
if (c == '\n')
line[i ] = '\n';
line[i] = '\0';
return i;
}
/* swap: interchange v[i] and v[j] */
void swap(void *v[], int i, int j)
{
void *temp;
temp = v[i];
v[i] = v[j];
v[j] = temp;
}
/* readlines: read input lines */
int readlines(char *lineptr[], int maxlines)
{
int len, nlines;
char *p, line[MAXLEN];
int getline(char *line, int max);
nlines = 0;
while ((len = getline(line, MAXLEN)) > 0)
{
p = (char*) calloc(len, sizeof(char*));
if ((nlines >= maxlines) || (p == NULL))
return -1;
if (strcmp(lineptr[nlines], "quit") == 0) {
free(p);
return 0;
}
line[len - 1] = '\0'; /* delete newline */
strncpy(p, line, len);
/* printf("%s\n", p); used for debugging */
strncpy(lineptr[nlines ], p, len);
free(p);
}
return nlines;
}
/* writelines: write output lines */
void writelines(char *lineptr[], int nlines)
{
int i;
for (i = 0; i < nlines; i )
printf("%s\n", lineptr[i]);
}
/* myqsort: sort v[left]...v[right] into increasing order */
void myqsort(void *v[], int left, int right,
int (*comp)(void *, void *))
{
int i, last;
void swap(void *v[], int i, int j);
/* return if there are less than 2 elements */
if (left >= right)
return;
swap(v, left, (left right) / 2);
last = left;
for (i = left 1; i <= right; i ) {
if ((*comp)(v[i], v[left]) < 0)
swap(v, last, i);
}
swap(v, left, last);
myqsort(v, left, last - 1, comp);
myqsort(v, last 1, right, comp);
}
/* numcmp: compare s1 and s2 numerically */
int numcmp(char *s1, char *s2)
{
double v1, v2;
v1 = strtod(s1, NULL);
v2 = strtod(s2, NULL);
if (v1 < v2)
return -1;
if (v1 > v2)
return 1;
return 0;
}
I think the issues reside around the readlines function and this may be a problem of memory management, but I don't understand it at all. It's been days and this is still causing me struggles, help me please. Thank you in advance.
EDIT: I tried to run gdb and this is what happened:
Reading symbols from sort.exe...
(gdb) r
Starting program: ...\sort.exe
[New Thread 3444.0x4f8c]
test
Thread 1 received signal SIGSEGV, Segmentation fault.
0x00007ffde739c160 in ucrtbase!strcmp () from C:\WINDOWS\System32\ucrtbase.dll
(gdb) backtrace
#0 0x00007ffde739c160 in ucrtbase!strcmp () from C:\WINDOWS\System32\ucrtbase.dll
#1 0x00007ff631a11a4f in readlines ()
#2 0x00007ff631a1182a in main ()
(gdb)
CodePudding user response:
Uninitialized variables:
In the readlines
functions:
while ((len = getline(line, MAXLEN)) > 0)
{
p = (char*) calloc(len, sizeof(char*));
if ((nlines >= maxlines) || (p == NULL))
return -1;
if (strcmp(lineptr[nlines], "quit") == 0) {
free(p);
return 0;
}
lineptr
is used uninitialized. It might be pointing to anything in memory, and as such it's contents are indeterminate and your code invokes undefined behaviour.
The original K&R code first copies the contents of line
to the pointer returned by calloc
(or the memory allocator they wrote), and then it's address is assigned to the -ith element of lineptr
on each iteration.
To cast or not to cast:
The memory allocation functions return a generic void pointer, or void *
that is automatically promoted to the correct type. There's no need to cast the result of malloc
and family.
A void pointer can be converted to/from any other pointer type without an explicit cast (C11 6.3.2.3 and 6.5.16.1).