How to Pass array from C to SV using SV-DPI? - c

My objective is to pass an array from C to SV and print the array contents in SV, I have tried the following C program of converting some text file(data_file.txt) (given full source in the link below) to an array and trying to read back the array by using DPI calls in SystemVeilog(SV), in "C" I have passed the array values to my function(mydisplay) which is inside the main func.(please correct me if I am wrong here) also it seems the array values are not read back to the SV environment as I would expect what could be the reason, is there an efficient way to get back the array in SV?
c code:
void mydisplay(svOpenArrayHandle h) {
int *a;
a =(int*)svGetArrayPtr(h);
for( i=0;i<idx;i++) {
io_printf("C: values[%2zu]=0x%02x\n",i,values[i]);
a[i] = values[i];
}
}
sv code:
program automatic top;
int a[32000];
import "DPI-C" function void mydisplay(inout int h[]);
initial begin
mydisplay(a);
foreach(a[i]) $display("SV after DPI: a[%0d]=%0d",i,a[i]);
end
endprogram
source at EDAplayground

After some trials I've finally found the solution and able to pass the processed text data from C to SV by a small tweak, I just imported a function and called the exported function using already available context method in the SV-DPI as per LRM, also only used the user defined function and removed the main from native "C" lang., this way I was able to read back the values in the array values from C to SV, provided below the code samples, updated code at EDAPlayground
C code:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strchr */
#include <limits.h> /* for INT_MIN/INT_MAX */
#include <errno.h> /* for errno */
extern int dV(int r);
#define MAXL 50000
unsigned long xstrtoul (char *p, char **ep, int base);
int mydisplay()
{
int v[15];
int sd;
int d;
FILE *fp = fopen ("data_file.txt", "r");
char line[MAXL] = {0};
unsigned values[MAXL] = {0};
int base = 16;
size_t i, idx = 0;
if (!fp) { /* validate file open */
fprintf (stderr, "error: file open failen '%s'.\n", fp);
return 1;
}
/* read each line in file (up to MAXL chars per-line) */
while (fgets (line, MAXL, fp)) {
char *p = line;
char *ep = p;
char digits[3] = {0};
errno = 0;
/* convert each string of digits into number */
while (errno == 0) {
/* skip any non-digit characters */
if (!(p = strchr (p, 'x'))) break;
strncpy (digits, ++p, 2);
digits[2] = 0; /* nul-terminate */
/* convert string to number */
values[idx++] = (unsigned)xstrtoul (digits, &ep, base);
if (errno || idx == MAXL) { /* check for error */
fprintf (stderr, "warning: MAXL values reached.\n");
break;
}
p += 2;
}
}
if (fp != stdin) fclose (fp);
/* print results */
for (i = 0; i < idx; i++)
{
printf ("C values[%2zu] : 0x%02x\t", i, values[i]);
v[d]=values[i];
sd = dV(v[d]);
}
return(sd);
}
/** string to unsigned long with error checking */
unsigned long xstrtoul (char *p, char **ep, int base)
{
errno = 0;
unsigned long tmp = strtoul (p, ep, base);
/* Check for various possible errors */
if ((errno == ERANGE && (tmp == ULONG_MAX)) ||
(errno != 0 && tmp == 0)) {
perror ("strtoul");
exit (EXIT_FAILURE);
}
if (*ep == p) {
fprintf (stderr, "No digits were found\n");
exit (EXIT_FAILURE);
}
return tmp;
}
SV code:
program automatic top();
int res;
import "DPI" context mydisplay= function int mD();
export "DPI" dV =function mydisplay;
function int mydisplay(input int xyz);
$display ("SV after DPI: %0d\n",xyz);
return -1;
endfunction
initial begin
#5 res=mD();
$display("Finished reading values...\n");
end
endprogram

Related

Reading File Into Struct Pointer

My file format is :
"name#totalMoney#ratio#luckyNumber"
I,m trying to read that into a dynamic struct pointer.(i want to use it like array)
I want to assign all the lines in the file to the struct array by assigning each line to an element of the struct array.My problem is when i compile this code only the first line of the file is read into struct array and nothing else.Thank for your helps..
#include"Person.h"
#include<stdio.h>
#include <stdlib.h>
#include <string.h>
#include<math.h>
#define NAMSZ 50//LENGTH FOR NAME BUFFER
void test_1(){
People *tmp=NULL;
int lengtPerson=pFileLength();//it returns number of line in the file
tmp=allocate_struct_array(&tmp,lengtPerson);
readPerson(&tmp);
}
void main(){
test_1();
}
#include"Person.h"//it contains declaration of the functions below and
/*typedef struct P{
char *name;
double totalMoney;
double ratio;
double luckyNumber;
} People; */
People *allocate_struct_array(People **parr,int total_line){
return *parr = malloc (total_line * sizeof **parr);
}
int readPerson(People **parr){
char c;
int MAXC=500;//max length of a line in the file
char buf[MAXC];
/* temporary array to hold each line */
int count = 0,
nparr = 0,
count_lines = 0;
FILE *fileptr = fopen ("Kisiler.txt", "r");
if (!fileptr) { /* always validate file open for reading */
perror ("fopen-fileptr");
}
while (nparr <= count_lines && fgets (buf, MAXC, fileptr)) {
char name[NAMSZ]; //temporary array for name
size_t len; // length of name
if (sscanf (buf, "%[^#]#%lf#%lf#%lf",name, &(parr[nparr]->totalMoney),
&(parr[nparr]->ratio),&(parr[nparr]->luckyNumber)) != 4) {
fputs ("error: invalid line format.\n", stderr);
continue;
}
len = strlen (name); // get length of name
parr[nparr]->name = malloc (len + 1); // allocate for name
if (!parr[nparr]->name) { // validate allocation
perror ("malloc-parr[nparr].name");
break;
}
memcpy (parr[nparr]->name, &name, len + 1);
nparr += 1;
}
for (int i = 0; i < nparr; i++) {
printf (" %-20s %8lf %5lf %5lf\n",
parr[i]->name,parr[i]->totalMoney,parr[i]->ratio,parr[i]->luckyNumber);
//free (parr[i].name); /* free strings when done */
}
//free (parr);
return count_lines;
fclose(fileptr);
}

How to sum up numbers from each lines in file in c?

I need to sum up the numbers from each line in the file like this e.g.:
1 2 3
10 -1 -3
and the result I should write to another file in each line likes this:
6
6
And I have the problem when in each line after the last number in reading file have more spaces, for example, maybe I use the '_' to show this problem:
When my function works:
10_11_12 '\n'
1_2_3 '\n'
and when my function doesn't work:
10_11_12_ _ _ '\n'
1_2_3 '\n'
I think I know where is the problem, but I have no idea how to fix it.
It's my function here:
int num=0;
char s;
while(fscanf(file, "%d", &num)==1){
fscanf(file, "%c", &s);
sum+=num;
if(s=='\n'){
fprintf(res_file, "%d\n", sum);
sum=0;
}
}
The problem is that fscanf is expecting a pointer to a char. Within your function, you are using a regular char, s.
char s;
You can fix your issue by making s a pointer. First, Allocate memory.
char *s = malloc(sizeof(char) + 1);
Now we can properly scan into the variable, s, and then check for the newline character. The only difference here is now we check for the newline by dereferencing s.
if (*s == '\n')
Don't forget to clean up the memory leak with free()!
free(s);
I was able to get the desired output using the code below.
#include <stdio.h>
#include <stdlib.h>
int processInputFile(char *filename)
{
FILE *ifp;
int buffer = 0;
char *newline = malloc(sizeof(char) + 1);
int sum = 0;
if ((ifp = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Failed to open \"%s \" in processInputFile.\n", filename);
return -1;
}
while(fscanf(ifp, "%d", &buffer) == 1)
{
fscanf(ifp, "%c", newline);
sum += buffer;
if (*newline == '\n')
{
printf("%d\n", sum);
sum = 0;
}
}
free (newline);
fclose(ifp);
}
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Proper syntax: ./a.out <n>\n");
return -1;
}
processInputFile(argv[1]);
return 0;
}
Any kind of line-by-line processing in C is easier done by reading the line first, and then processing it. fgets(3) handles end-of-line for you; then you just need to scan what it read. Plus, in the real world, some lines won't scan: either they'll have errors, or your scan won't be general enough. When that happens, it's awfully handy to write the input to standard error, so you can see what you're looking at.
Here's a complete program that does what you want. It assumes lines are less than 80 bytes long and doesn't protect against invalid input, though.
#include <stdio.h>
#include <err.h>
int main( int argc, char *argv[] ) {
char line[80];
static const char *filename = "sum.dat";
FILE *input;
if( (input = fopen(filename, "r")) == NULL ) {
err(1, "could not open %s", filename);
}
for( int nlines = 0;
fgets(line, sizeof(line), input) != NULL;
nlines++ )
{
double value, sum = 0;
int n;
for( char *p = line; sscanf(p, "%lf%n", &value, &n) > 0; p += n ) {
sum += value;
}
printf( "line %d: sum = %lf\n", nlines, sum );
}
return 0;
}
Reading with a line-oriented input function like fgets() or POSIX getline() ensures that a complete line of input is consumed on each call. (don't skimp on buffer size). strtol was created to convert an unknown number of values per-line into long. You walk-a-pointer down your buffer by utilizing the endptr parameter filled by strtol after a successful conversion to point to the next character after the last digit converted.
This allows a simple method to use a pair of pointers, p your start-pointer and ep your end-pointer to work through an entire line converting values as you go. The basic approach is to call strtol, validate it succeeded, and then set p = ep; to advance to the start of your next conversion. strtol ignores leading whitespace.
Putting it altogether, you could do:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
/* (don't skimp on buffer-size) */
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line read */
size_t n = 0; /* line-counter */
/* use filename provided as 1st argument (stdin by default) */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
perror ("file open failed");
return 1;
}
while (fgets (buf, MAXC, fp)) { /* read each line */
char *p = buf, *ep = p; /* pointer and end-pointer */
int sum = 0; /* variable to hold sum */
if (*buf == '\n') /* ignore empty lines */
continue;
while (*p && *p != '\n') {
errno = 0;
long tmp = strtol (p, &ep, 0); /* convert to temp long */
if (p == ep) { /* validate digits were converted */
fputs ("error: no digits extracted.\n", stderr);
break;
}
else if (errno) { /* validate no under/overflow occurred */
fputs ("error: underflow/overflow occurred.\n", stderr);
break;
}
else if (tmp < INT_MIN || INT_MAX < tmp) { /* validate in range */
fputs ("error: tmp exceeds range of int.\n", stderr);
break;
}
sum += tmp; /* add tmp to sum */
p = ep; /* set p to end-ptr (one past last digit used) */
}
n++; /* advance line counter */
printf ("sum line [%2zu] : %d\n", n, sum); /* output sum */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
(note: the if (*buf == '\n') which tests if the first character in the line is a newline character and simple skips to the next line, no need to worry about converting values in a empty line)
Example Use/Output
Using your data in dat/sumlines.txt produces the expected results.
$ ./bin/sumline dat/sumlines.txt
sum line [ 1] : 6
sum line [ 2] : 6
Let me know if you have further questions.

qsort fails to sort large array of strings

I'm using qsort to sort an array of i strings of size 256, such as char *arr = malloc(i * 256) -- was actully done with reallocs inside a loop. Each string contains, among text, a number, which I use as the comparison element:
int
cmp(const void *a, const void *b)
{
double atime = get_time((char*)a);
double btime = get_time((char*)b);
return (atime > btime) - (atime < btime);
}
When i is small, it works. With a large i, it fails to sort the array correctly. get_time is working. I was using it with a custom heapsort implementation before, which worked flawlessly.
I added the following to cmp to check what was happening:
fprintf(stderr, "Comparing %f to %f, result: %d.\n", atime, btime, (atime > btime) - (atime < btime));
It seems that all comparisons are correct, but not all comparisons are being made. arr has several strings containing 1.something, however I couldn't find any comparison between numbers greater than 1 in the output. The call to qsort is as follows:
qsort((void*)arr, i-1, MAX_ROW_LEN, cmp);
It's the same parameters I used to pass to my heapsort function, but it doesn't work.
Complete code, and example file (fails to sort).
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define MAX_ROW_LEN 256
#define MAX_FILENAME_LEN 256
/* Return the start time of the event or -1 if no time. */
static double
get_time(const char *event)
{
if (!event || event[0] == '%')
return -1;
size_t tok = strcspn(event, " ") + 2;
double ans = strtod(event + tok, NULL);
if (!ans)
return -1;
return ans;
}
/*static inline*/ int
cmp(const void *a, const void *b)
{
double atime = get_time((char*)a);
double btime = get_time((char*)b);
return (atime > btime) - (atime < btime);
}
int
main(int argc, char **argv)
{
/* process parameters */
if (argc < 2) {
fprintf(stderr, "Supply a file to sort.\n");
exit(EXIT_FAILURE);
}
if (strlen(argv[1]) > MAX_FILENAME_LEN) {
fprintf(stderr, "Filename too long.\n");
exit(EXIT_FAILURE);
}
/* read the file */
printf("Now processing %s.\n", argv[1]);
FILE *f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "Failed to open out. Errno %d.\n", errno);
exit(EXIT_FAILURE);
}
char *trace = malloc(MAX_ROW_LEN);
char *header = malloc(MAX_ROW_LEN);
size_t i = 1, j = 1;
while (fgets(trace + (i-1)*MAX_ROW_LEN, MAX_ROW_LEN, f)) {
/* (if we can't get the time, it's part of the header) */
if (get_time(trace + (i-1)*MAX_ROW_LEN) != -1) {
trace = realloc((void*)trace, (++i)*MAX_ROW_LEN);
} else {
strncpy(header + (j-1)*MAX_ROW_LEN, trace + (i-1)*MAX_ROW_LEN,
MAX_ROW_LEN);
header = realloc((void*)header, (++j)*MAX_ROW_LEN);
}
}
if (!feof(f)) {
fprintf(stderr, "Error reading file. Errno %d.\n", ferror(f));
exit(EXIT_FAILURE);
}
printf("Read %zu lines.\n", i);
fclose(f);
/* write the header */
f = fopen("out_fixed", "w");
if (!f) {
fprintf(stderr, "Failed to open out_fixed. Errno %d.\n", errno);
exit(EXIT_FAILURE);
}
for (size_t k = 0; k < j-1; ++k) {
/* (there is '%' in comments, can't print formatted) */
fputs((void*)(header + k*MAX_ROW_LEN), f);
}
/* sort */
printf("Started sorting.\n");
time_t start = time(NULL);
qsort((void*)trace, i-1, MAX_ROW_LEN, cmp);
printf("Ended sorting, took %fs.\n", difftime(time(NULL), start));
/* write the sorted trace */
printf("Started writting to disk.\n");
start = time(NULL);
for (size_t k = 0; k < i-1; ++k) {
fprintf(f, "%s", trace + k*MAX_ROW_LEN);
}
printf("Took %fs.\n", difftime(time(NULL), start));
/* flush */
printf("Closing file (fflush)\n");
start = time(NULL);
if (fclose(f)) {
fprintf(stderr, "Failed to close out_fixed. Errno %d.\n", errno);
exit(EXIT_FAILURE);
}
printf("Took %fs.\n", difftime(time(NULL), start));
exit(EXIT_SUCCESS);
}
I've tested your code and your example input file and it seems to work fine. In your question you say:
... has several strings containing 1.something, however I couldn't find
any comparison between numbers greater than 1 in the output.
But there are no such lines in your example input file.
Given this example line of your input:
12 0.475183170 rank3 STATE fill_row
This line in get_time is going to skip over any leading digits in your double:
size_t tok = strcspn(event, " ") + 2;
strcspn returns the number of characters that it had to read before finding the "needle" so in this case it will return 2. You then add 2 to that and then use that as a pointer offset into your event string, meaning that you are passing a pointer to .475183170 instead of 0.475183170.
You'd be better off just using strchr here anyway:
char *tok = strchr(event, ' ');
if (!tok) {
return -1;
}
double ans = strtod(tok, NULL);
The subsequent strtod will skip leading whitespace for you, so you don't need to get super fancy.

How to sort lines of file depending on value at end of each line

I'm trying to create a program that takes an input file and sorts it to a new output file in ascending order depending on the number at the end of each line. For example, if the input file contains three lines below:
a good man 50
65
better are 7
The corresponding sorted output file would be three lines but sorted:
better are 7
a good man 50
65
Code I have so far:
int sortLines(char * inputFileName, char * outputFileName)
{
FILE *fpin = fopen(inputFileName, "r");//open file to to read
if (!fpin)
{
printf("Error in file opening\n");
exit (-1);
}
FILE *fpout = fopen(outputFileName, "w");//open file to to write
if (!fpout)
{
printf("Error in opfile opening\n");
exit (-1);
}
char file[10][1024];
int i = 0;
while(fgets(file[i], sizeof(file[i]), fpin))
i++;
int total = i;
for(i = 0; i<total; ++i)
printf("%s", file[i]);
return 0;
}
Continuing on from the comment, you can read the lines into a struct (containing the line and an int), then use strrchr to find the last space in each line (or if null, just take the whole line), convert the string with strtol or atoi or the like to set the int field of struct. Then it is a simple matter of sorting the structs based on the int member. I'll leave the reading into the struct to you, the sorting example is:
#include <stdio.h>
#include <stdlib.h>
#define MAXL 32
struct data {
char line[MAXL];
int n;
};
int compare_n (const void *a, const void *b)
{
struct data *ia = (struct data *)a;
struct data *ib = (struct data *)b;
return (int)(ia->n - ib->n);
}
int main (void)
{
struct data lines[] = {{"a good man 50", 50}, {"65", 65}, {"better are 7", 7}};
size_t nstr = sizeof lines / sizeof *lines;
size_t i = 0;
qsort (lines, nstr, sizeof *lines, compare_n);
for (i = 0; i < nstr; i++)
printf (" %s\n", lines[i].line);
return 0;
}
Output
$ ./bin/struct_sort_int
better are 7
a good man 50
65
full example
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXL 64
/* simple struct holding char array and int */
struct data {
char line[MAXL];
int n;
};
/* qsort comparison function for int 'n' */
int compare_n (const void *a, const void *b)
{
struct data *ia = (struct data *)a;
struct data *ib = (struct data *)b;
return (int)(ia->n - ib->n);
}
int main (int argc, char **argv)
{
if (argc < 2 ) { /* validate at least 1 argument provided */
fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
return 1;
}
struct data lines[MAXL] = {{{0}, 0}}; /* array of struct */
char *ln = NULL; /* buffer for getline, getline allocates */
size_t n = 0; /* initial size of buf, 0 getline decides */
ssize_t nchr = 0; /* getline return, no. of chars read */
size_t idx = 0; /* index for array of struct */
size_t i = 0; /* general iteration variable */
FILE *fp = NULL; /* file pointer for input file */
if (!(fp = fopen (argv[1], "r"))) { /* validate file open */
fprintf (stderr, "error: file open failed. '%s'\n", argv[1]);
return 1;
}
/* read each line in file */
while ((nchr = getline (&ln, &n, fp)) != -1)
{
while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
ln[--nchr] = 0; /* strip newline or carriage rtn */
if (!nchr) continue; /* skip blank lines */
if (nchr > MAXL - 1) { /* test for line > MAXL -1 */
fprintf (stderr,
"warning: line will exceeded %d chars.\n", MAXL);
continue; /* number at end invalid */
}
strcpy (lines[idx].line, ln); /* copy to struct.line */
char *p = NULL;
if (!(p = strrchr (ln, ' '))) /* pointer to last space */
p = ln; /* if no space, then line */
lines[idx].n = atoi (p); /* convert string to int */
idx++; /* increment index */
if (idx == MAXL) { /* if MAXL read, break */
fprintf (stderr, "warning: %d lines read.\n", MAXL);
break;
}
}
if (fp) fclose (fp); /* close input file */
if (ln) free (ln); /* free line buffer mem */
qsort (lines, idx, sizeof *lines, compare_n); /* sort struct */
for (i = 0; i < idx; i++) /* print sorted array */
printf (" %s\n", lines[i].line);
return 0;
}
Take a look and let me know if you have questions. Your data was in the file dat/endno.txt for my test. I'll add comments when I get a chance.
note: updated to skip blank lines and to check line length against MAXL to eliminate the possibility of a write beyond end of lines and skip lines that would be truncated rendering the number at end invalid.
without struct statically allocated arrays
The following is an example that uses two 2D arrays, one for the lines and then one holding the original line index and number at end of line. Unlike the dynamically allocated example below, this example is limited to reading MAXL lines from the file or no more than MAXS characters each. If a line is exactly MAXS characters long (including the null-terminator), it must be discarded, because there is no way of knowing if the number at end remains valid. The 2D array containing the line index and number at end is sorted based on the number at end, then lines are printed based on the original line index resulting in the lines printing in sorted order by number at end. While this may look simpler, it is far more limited than the method utilizing the struct or the dynamically allocated approach below. This is about all I can think to do to get your going. Good luck. Drop a line if you have questions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXL 64
#define MAXS 128
int cmpint (const void *a, const void *b);
int main (int argc, char **argv) {
if (argc < 2 ) { /* validate at least 1 argument provided */
fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
return 1;
}
int numidx[MAXL][2] = {{0}}; /* array of integers */
char lines[MAXL][MAXS] = {{0}}; /* array of strings */
char ln[MAXS] = {0}; /* buffer for fgets, MAXS in length */
ssize_t nchr = 0; /* getline return, no. of chars read */
size_t idx = 0; /* index for array of struct */
size_t i = 0; /* general iteration variable */
FILE *fp = NULL; /* file pointer for input file */
if (!(fp = fopen (argv[1], "r"))) { /* validate file open */
fprintf (stderr, "error: file open failed. '%s'\n", argv[1]);
return 1;
}
/* read each line in file */
while (fgets (ln, MAXS, fp) != NULL)
{
nchr = strlen (ln); /* get length of ln */
while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
ln[--nchr] = 0; /* strip newline or carriage rtn */
if (!nchr || nchr == MAXS - 2) /* skip blank lines + full */
continue; /* lines (end no. invalid) */
strcpy (lines[idx], ln); /* copy ln to lines[idx] */
char *p = NULL;
if (!(p = strrchr (ln, ' '))) /* pointer to last space */
p = ln; /* if no space, then line */
numidx[idx][0] = atoi (p); /* save end no. in array */
numidx[idx][1] = idx; /* save line index in array */
idx++; /* increment index */
if (idx == MAXL) { /* if MAXL read, break */
fprintf (stderr, "warning: %d lines read.\n", MAXL);
break;
}
}
fclose (fp);
qsort (numidx, idx, sizeof (int) * 2, cmpint);/* sort array */
for (i = 0; i < idx; i++) /* print sorted array */
printf (" %s\n", lines[numidx[i][1]]);
return 0;
}
/* qsort integer compare function */
int cmpint (const void *pa, const void *pb )
{
const int *a = pa;
const int *b = pb;
if (a[0] < b[0])
return -1;
return (b[0] < a[0]);
}
without struct, dynamically allocated arrays
To get around using a structure to hold the string an number, you can use 2 arrays. One to hold the strings, and another 2D array holding the original line index and number at end of line (2 integers). You then qsort the integer array on the (number at end) element, then loop through each line printing out the lines in sorted order based on the line index value of the sorted array. This is set to handle lines of any length and reallocate the number of lines (in each array) as needed. Since the dynamic allocation may be a bit much, I'm working on a static array version as well, but it will be tomorrow before I have time. Here is the first version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXL 64
int cmpint (const void *a, const void *b);
char **realloc_char (char **sp, size_t *n);
int **realloc_int (int **ip, size_t *n);
int main (int argc, char **argv) {
if (argc < 2 ) { /* validate at least 1 argument provided */
fprintf (stderr, "error: insufficient input, usage: %s filename\n", argv[0]);
return 1;
}
int **numidx = NULL; /* array of pointers-to-pointer-to-int */
char **lines = NULL; /* array of pointer-to-pointer-to-char */
char *ln = NULL; /* buffer for getline, getline allocates */
size_t n = 0; /* initial size of buf, 0 getline decides */
ssize_t nchr = 0; /* getline return, no. of chars read */
size_t idx = 0; /* index for array of struct */
size_t i = 0; /* general iteration variable */
size_t maxl = MAXL; /* holds current allocation size of arrays */
FILE *fp = NULL; /* file pointer for input file */
if (!(fp = fopen (argv[1], "r"))) { /* validate file open */
fprintf (stderr, "error: file open failed. '%s'\n", argv[1]);
return 1;
}
/* allocate MAXL pointers to int* */
if (!(numidx = calloc (MAXL, sizeof *numidx))) {
fprintf (stderr, "error: memory allocation failed.\n");
return 1;
}
/* allocate MAXL pointers to char* */
if (!(lines = calloc (MAXL, sizeof *lines))) {
fprintf (stderr, "error: memory allocation failed.\n");
return 1;
}
/* read each line in file */
while ((nchr = getline (&ln, &n, fp)) != -1)
{
while (nchr > 0 && (ln[nchr-1] == '\n' || ln[nchr-1] == '\r'))
ln[--nchr] = 0; /* strip newline or carriage rtn */
if (!nchr) continue; /* skip blank lines */
lines[idx] = strdup (ln); /* copy ln to lines[idx] */
/* allocate space for 2 int at numidx[idx] */
if (!(numidx[idx] = calloc (2, sizeof **numidx))) {
fprintf (stderr, "error: memory allocation failed.\n");
return 1;
}
char *p = NULL;
if (!(p = strrchr (ln, ' '))) /* pointer to last space */
p = ln; /* if no space, then line */
numidx[idx][0] = atoi (p); /* save end no. in array */
numidx[idx][1] = idx; /* save line index in array */
idx++; /* increment index */
if (idx == maxl) { /* if idx = maxl reallocate */
size_t tsz = maxl; /* tmp var, each get maxl */
numidx = realloc_int (numidx, &tsz);
lines = realloc_char (lines, &maxl);
}
}
if (ln) free (ln);
fclose (fp);
qsort (numidx, idx, sizeof *numidx, cmpint); /* sort struct */
for (i = 0; i < idx; i++) /* print sorted array */
printf (" %s\n", lines[numidx[i][1]]);
for (i = 0; i < idx; i++) { /* free allocated memory */
free (numidx[i]);
free (lines[i]);
}
free (numidx);
free (lines);
return 0;
}
/* qsort integer compare function */
int cmpint (const void *a, const void *b)
{
const int **ia = (const int **)a;
const int **ib = (const int **)b;
return (*ia)[0] - (*ib)[0];
}
/** realloc an array of pointers to strings setting memory to 0.
* reallocate an array of character arrays setting
* newly allocated memory to 0 to allow iteration
*/
char **realloc_char (char **sp, size_t *n)
{
char **tmp = realloc (sp, 2 * *n * sizeof *sp);
if (!tmp) {
fprintf (stderr, "Error: struct reallocation failure.\n");
// return NULL;
exit (EXIT_FAILURE);
}
sp = tmp;
memset (sp + *n, 0, *n * sizeof *sp); /* memset new ptrs 0 */
*n *= 2;
return sp;
}
/** realloc an array of pointers to int* setting memory to 0.
* reallocate an array of integer arrays setting
* newly allocated memory to 0 to allow iteration
*/
int **realloc_int (int **ip, size_t *n)
{
int **tmp = realloc (ip, 2 * *n * sizeof *ip * 4);
if (!tmp) {
fprintf (stderr, "Error: struct reallocation failure.\n");
// return NULL;
exit (EXIT_FAILURE);
}
ip = tmp;
memset (ip + *n, 0, *n * sizeof *ip * 4); /* memset new ptrs 0 */
*n *= 2;
return ip;
}
You could read the entire file into a single buffer, create an array of structures containing pointers to lines and the values at the end of each line (scan for newline characters), then sort the array of structures by the values, and output the data according to the pointers in the sorted array of structures.

Error LNK2019: unsresolved external symbol

Hey I'm getting this error and I'm not sure why. I'm pretty new to C so hopefully it won't be too complicated.
heres my main
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "binToDec.c"
#include "verifyMIPS.c"
int binToDec(char string[], int begin, int end);
int verifyMIPS (char string[]);
int main(int argc, char *argv[])
{
char buffer[BUFSIZ];
FILE* fptr; /* file pointer */
int lineNum = 0;
int i;
char *count;
/* Was a file passed in a parameter (e.g., on the command line)? */
if ( argc == 2 )
{
/* Open the file for reading */
if ((fptr = fopen (argv[1], "r")) == NULL)
{
fprintf (stderr, "Error: Cannot open file %s.\n", argv[1]);
return 1;
}
}
else /* No file passed in; use standard input. */
fptr = stdin;
/* Continuously read next line of input until EOF is encountered.
* Each line should contain only 32 characters and newline.
*/
while (fgets (buffer, BUFSIZ, fptr)) /* fgets returns NULL if EOF */
{
lineNum++;
if (strlen (buffer) == 33 && buffer[32] == '\n')
buffer[32] = '\0'; /* convert newline to null byte */
else
{
(void) fprintf (stderr,
"Error: line %d does not have 32 chars.\n", lineNum);
continue; /* error: get next line */
}
/* Verify that the string is 32 0's and 1's. If it is, do
* various tests to ensure that binToDec works correctly.
* If the string contains invalid characters, print an error
* message.
*/
/* CODE MISSING !!! */
int i;
for(i=0; i<33; i++)
{
if(verifyMIPS(buffer[i])==1)
{
binToDec(buffer[i],0,32);
}
else
{
(void) fprintf (stderr,
"Error: line %d does not have 32 chars.\n", lineNum);
continue; /* error: get next line */
}
}
}
/* End-of-file encountered; close the file. */
fclose (fptr);
return 0;
}
and now my two other files
#include <string.h>
int verifyMIPSInstruction (char * instr)
/* returns 1 if instr contains 32 characters representing binary
* digits ('0' and '1'); 0 otherwise
*/
{
int i;
for(i = 0; i<32; i++)
{
if(instr[i] == '1' || instr[i] == '0')
{
return 1;
}
}
if(instr[32] != '\0')
{
(void) printf("is not an instruction");
}
return 0;
}
and
int binToDec(char string[], int begin, int end)
{
int i, remainder;
int j = 1;
int decimal = 0;
i = atoi(string);
while(i !=0)
{
remainder = i%10;
decimal = decimal+remainder*j;
j=j*2;
i = i/10;
}
printf("equivalent decimal value: %i", decimal);
return decimal;
}
the output I'm getting is
error LNK2019: unresolved external symbol _verifyMIPS referenced in function _main
I'm also using the Microsoft Visual Studios developer command prompt for all of this.
Thanks for your help!
EDIT: new problem, When I run the code, and I put in 32 characters, it will not run verifyMIPSInstructions or binToDec. It will only give me the error that it doesn't have 32 characters when it clearly does. Any advice?
I agree with the linker. I don't see the verifyMIPS() function ether. Perhaps main() should call verifyMIPSInstruction() instead?

Resources