Related
I am trying to sort the following structure. I am using the qsort to order the books according to date publish in order of the newest first. I completely don't understand why the pointer can't access the date-published element.
#include <string.h>
#include <stdlib.h>
#include "problem5.h"
int int_cmp(const void *a, const void *b)
{
//const int *ia = (const int *)a;
//const int *ib = (const int *)b;
//return *ia - *ib;
return (*(int*)a - *(int*)b);
}
int main()
{
struct book* books = NULL; // no books at all initially so we initialize to NULL
// so we can simply use realloc
int numberofbooks = 0;
int programend = 0;
while (programend == 0)
{
printf("1. Add Book\n");
printf("2. View Books\n");
printf("3. Quit\n");
int command;
int i, j;
scanf("%d", &command);
if (command == 1)
{
getchar(); // consume Enter key (due su scanf)
// allocate memory for one more book
books = realloc(books, sizeof(struct book) * (numberofbooks + 1));
printf("Enter Name\n");
gets(books[numberofbooks].name);
printf("Enter Author\n");
gets(books[numberofbooks].author);
printf("Enter Year Published\n");
scanf("%d", &books[numberofbooks].year_published);
numberofbooks++; // increment number of books
printf(books.year_published);
}
else if (command == 2)
{
qsort(books->year_published, numberofbooks, sizeof(int), int_cmp);
for (i = 0; i < numberofbooks; i++)
{
printf("%d - %s by %s\n", books[i].year_published, books[i].name, books[i].author);
}
}
else if (command == 3)
{
programend = 1;
}
//else if and the else will prevent infinite loop when the user enters invalid choice in the beginning.
else if (command != 1 || command != 2 || command != 3)
{
printf("Invalid choice!\n");
}
else {return 0;}
}
free(books);
return 0;
}
I think the problem is the pointer in the qsort() but I don't know how to correct that. I tried using qsort(books, numberofbooks, sizeof(int), int_cmp); but the books weren't ordered as expected.
Here is an example of a multikey sort:
int
cmp_multikey(const void *a,const void *b)
{
const struct book *booka = a;
const struct book *bookb = b;
int cmp;
do {
// sort by year published
cmp = booka->year_published - bookb->year_published;
if (cmp)
break;
// sort by author
cmp = strcmp(booka->author,bookb->author);
if (cmp)
break;
// sort by title
cmp = strcmp(booka->name,bookb->name);
if (cmp)
break;
} while (0);
return cmp;
}
Invoke with:
qsort(books,numberofbooks,sizeof(struct book),cmp_multikey);
Some other tips ...
[As others have mentioned] Never use gets. Use a switch/case instead of an if/else ladder.
Try to avoid intermixing scanf and fgets.
Personally, I prefer to [always] use fgets. Here is a [safe] replacement for gets and a replacment for scanf("%d",&num);:
int
getstr(const char *prompt,char *buf,int buflen)
{
char *cp;
printf("%s",prompt);
fflush(stdout);
cp = fgets(buf,buflen,stdin);
if (cp == NULL) {
fprintf(stderr,"unexpected EOF\n");
exit(1);
}
// find newline
cp = strchr(buf,'\n');
// ensure we had enough space
if (cp == NULL) {
fprintf(stderr,"response too large for buffer\n");
exit(1);
}
// strip newline
*cp = 0;
}
int
getnum(const char *prompt)
{
char buf[1000];
int num;
getstr(prompt,buf,sizeof(buf));
num = atoi(buf);
return num;
}
I'm new here, so this is my first post. I've been struggling for 2 weeks to solve this problem. I'm trying to open a directory, capture and store the names of the files found, sort them in ascending order, and print the results. My issue is either qsort causes my program to crash entirely, or qsort doesn't sort the array at all because the files are alphanumeric. I even tried looping through a stored filename to output each character, just to see if I could eventually try comparing the characters between two array locations for sorting. But I noticed that it can't seem to see or recognize the numbers in the alphanumeric filename (for example: "f1.jpg" will only print "f", a blank, then "j", and that's it. I should note that I cannot change the file names because I don't know in advance the names or total files. I'm trying to make this to be dynamic. The following is the main code that I'm having problems with since it crashes at the 'qsort' keyword:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <conio.h>
#include <ctype.h>
#include <time.h>
#include <dirent.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int compare(const void *a, const void *b);
void readInFilenames();
int main
{
readInFilenames();
system("pause");
}
int compare(const void *a, const void *b)
{
return strcmp(*(char **)a, *(char **)b);
}
void readInFilenames()
{
char cwd[1024];
DIR *dir = NULL;
struct dirent *pent = NULL;
struct stat info;
char file_path[50] = "files/";
int total_files = 0;
int file_size;
// Change directory to file location
chdir(file_path);
if((getcwd(cwd, sizeof(cwd))) != NULL)
{
printf("Current Directory: %s\n", cwd);
}
// Open directory and count the total number of files found
dir = opendir(cwd);
if(dir != NULL)
{
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
total_files++;
file_size = sizeof(pent->d_name);
}
}
}
}
printf("# of files found: %d\n", total_files);
rewinddir(dir); //reset pointer back to beginning of file directory
// Create character array to store file names;
char *filenames_arr[total_files][file_size];
int size = sizeof(filenames_arr)/sizeof(filenames_arr[total_files]);
total_files = 0; //reset file counter back to 0;
// Read and store file names in the character array
while((pent = readdir(dir)) != NULL)
{
if(stat(pent->d_name, &info))
{
printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
}
else
{
if(S_ISREG(info.st_mode))
{
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
strcpy(filenames_arr[total_files], pent->d_name);
//printf("%s\n", filenames_arr[i]);
total_files++;
}
}
}
}
closedir(dir);
// Print original array contents
printf("Original List of Files\n");
printf("----------------------\n");
for(int i = 0; i < total_files; i++)
{
printf("%s\n", filenames_arr[i]);
}
// Sort array in ascending order
qsort(filenames_arr, total_files, size, compare);
//qsort(filenames_arr, total_files, sizeof(filenames_arr[0]), (char (*)(const void*, const void*))strcmp);
// Print organized array contents
printf("Sorted List of Files\n");
printf("----------------------\n");
for(int i = 0; i < total_files; i++)
{
printf("%s\n", filenames_arr[i]);
}
printf("\nFinished!\n");
}
}
This portion of code is when I was trying to print each individual characters. This was originally located where the final array printing takes place in the previous code:
int i = 0;
int j = 0;
while(i < total_files)
{
printf("File Name: %s\n", filenames_arr[i]);
printf("String Length: %d\n", strlen(filenames_arr[i]));
while(filenames_arr[i] != '\0')
{
printf("Checking filenames_arr[%d][%d]\n", i, j);
if(isalpha((unsigned char)filenames_arr[i][j]) != 0)
{
printf("In isalpha\n");
printf("Found: %c\n", filenames_arr[i][j]);
}
else if(isdigit((unsigned char)filenames_arr[i][j]) != 0)
{
printf("In isdigit\n");
printf("Found: %d\n", filenames_arr[i][j]);
}
j++;
}
printf("-------------------------------------------\n");
i++;
j = 0;
}
How do I sort a 2D array of alphanumeric character strings using qsort? What is it about qsort, or even my array setup that's causing my program to crash? Also, how does qsort work? I've tried searching forums and online course notes to find out whether or not qsort only sorts by looking just at the first character, all characters, or if it has problems with numbers. Thank you in advance!
UPDATE:
I made the following edits to my code. Its working much better, in that qsort no longer crashes program. But, qsort still isn't sorting. Here are the updates I made, followed by a screenshot of the results:
typedef struct{
char *filename;
}filedata;
int compare(const void *a, const void *b);
void readInFilenames();
int main(void){
readInFilenames();
system("pause");
}
int compare (const void *a, const void *b ) {
filedata *ia = (filedata *)a;
filedata *ib = (filedata *)b;
return strcmp(ia->filename, ib->filename);
}
readInFilenames(){
.
.
.
printf("# of files found: %d\n", total_files);
rewinddir(dir);
filedata fn_data[total_files];
total_files = 0;
printf("Original Array: \n");
while((pent = readdir(dir)) != NULL)
{
.
.
.
if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
{
continue;
}
else
{
fn_data[total_files].filename = malloc(file_size + 1);
strcpy(fn_data[total_files].filename, pent->d_name);
printf("%s\n", fn_data[total_files].filename);
total_files++;
}
}
closedir(dir);
printf("\n");
qsort(fn_data, total_files, sizeof(filedata), compare);
printf("Sorted Array:\n");
for(int i = 0; i < total_files; i++)
printf("%s\n", fn_data[i].filename);
printf("Finished!\n");
}
Click here to see sorting results
The list should print: f0.dat, f1.dat, f2.dat, f3.dat,...,f20.dat. But instead it prints: f0.dat, f1.dat, f10.dat, f11.dat,...,f9.dat.
OP has fixed code to cope with "qsort dynamic 2d char array with filenames" by enabling warnings and using #Snohdo advice.
Yet code is still doing a compare with strcmp() which only treat digits as characters and not numerically to achieve f1.dat, f2.dat, f3.dat,...,f20.dat order.
Following is a compare functions that looks for digits to invoke an alternate compare for numeric sub-strings. Variations on this compare can be made by OP to suit detailed coding goals.
int AdamsOrder(const char *s1, const char *s2) {
// Compare as `unsigned char` as that is `strcmp()` behavior. C11 7.24.1 3
const unsigned char *us1 = (const unsigned char *) s1;
const unsigned char *us2 = (const unsigned char *) s2;
while (*us1 && *us2) {
if (isdigit(*us1) && isdigit(*us2)) {
char *end; // dummy
unsigned long long l1 = strtoull(us1, &end, 10); // Parse for a number
unsigned long long l2 = strtoull(us2, &end, 10);
if (l1 > l2) return 1;
if (l1 < l2) return -1;
// Continue on treating as text. OP needs to decide how to handle ties: "0001" vs "1"
}
if (*us1 > *us2) return 1;
if (*us1 < *us2) return -1;
us1++;
us2++;
}
// At this point, at least one string ended (i.e. points to '\0').
// The return statement below will behave as follows:
// If a string ended, *us1/2 will be 0. Let an unfinished one be X > 0.
// First string ended : ( 0 > X ) - ( 0 < X ) = false - true = 0 - 1 = -1
// Second string ended: ( X > 0 ) - ( X < 0 ) = true - false = 1 - 0 = 1
// Both strings ended : ( 0 > 0 ) - ( 0 < 0 ) = false - false = 0 - 0 = 0
return (*us1 > *us2) - (*us1 < *us2);
}
I'm writing a simple banking application in c
It saves the information in a file.
I want to load the file each time the app runs, and add the information from the file to the struct, for this purpose, I have written two functions called "loadfile" and "allocate"
In the function "loadfile" if I un-comment the comment lines, the OS throws a "stopped working" in my face :|
Can you help me with it ?
when I use (acc+i) in the "loadfile", the error shows up.
Is there a syntax problem? :o
thanks
typedef struct {
char name[20];
int id;
int balance;
char branch[10];
} account;
account *acc;
int allocate ( account *acc ) {
int num = 0 ;
char tempname[20],tempbranch[10];
int tempid = -1 ,tempbalance;
FILE *file;
file = fopen("D://bank.txt","r");
while ( !feof(file) ) {
fscanf(file,"%s %d %d %s ",tempname, &tempid, &tempbalance, tempbranch);
if (tempid != -1)
num++;
}
acc = ( account *) realloc ( acc, num * sizeof(account) );
fclose(file);
printf(" num in allocate function : %d",num);
return num;
}
int loadfile (account *acc) {
int num = allocate(acc);
char tempname[20],tempbranch[10];
int tempid ,tempbalance;
if ( num != 0 ) {
int i = 0 ;
FILE *file;
file = fopen("D:\\bank.txt","r+");
for ( i = 0 ; !feof(file) && i < num ; i++ ) {
fscanf(file,"%s ",tempname );
fscanf(file,"%d ",&tempid );
fscanf(file,"%d ",&tempbalance );
fscanf(file,"%s ",tempbranch );
printf("\n i is %d \n",i);
/* strcpy( ((acc+i)->name) , tempname);
(acc+i)->id = tempid;
(acc+i)->balance = tempbalance;
strcpy( ((acc+i)->branch) , tempbranch); */
}
fclose(file);
}
return num;
}
There are a lot of issues with the posted code. It is unclear how a separate allocation function is helpful, and the use of the file-scope variable acc is not advisable. I see no point in using realloc() here, since allocation is done only once. If you do use realloc(), you should store the result in a temporary pointer, because the function can return a NULL pointer if there is an allocation error. This leads to a memory leak if you assign directly to the pointer that you are reallocating from. I have rewritten the code to illustrate some fixes, trying to maintain the general structure of the original code.
You should check the return values of the functions that you call. realloc() and malloc() return a pointer to the allocated memory, or a NULL pointer in the event of an allocation error. You should check this value and handle the result. The scanf() functions return the number of successful assignments made. You should check this value to verify that input is as expected. It is almost always a bad idea to control a loop with feof(), because this function relies upon the end-of-file indicator being set, and this indicator is only set when an I/O operation has failed.
In the program below, fgets() is used to read a line of input from the file into a buffer, and sscanf() is used to extract the input data from the buffer. In the allocation phase, EOF or an empty line signals the end of the data. No parsing is done here, only a count of lines. For each line, space is allocated for an account. Note that the code checks for errors on opening and closing the file, as well as for an allocation error.
The loadfile() function again uses fgets() to read a line of input into buffer, and then uses sscanf() to scan the buffer. Note the use of width specifiers for the strings. These are one less than the size of the arrays that they read into, to leave space for the '\0' placed at the end of the strings by sscanf(). Also note that in the event that fewer than 4 assignments are made, the program exits with an error message. If the assignments to the temporary variables were successful, the account is updated with the data.
There are many ways that this code could be improved (most obviously by getting rid of the global variable acc), but this should provide you with a good starting point.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char name[20];
int id;
int balance;
char branch[10];
} account;
account *acc = NULL;
int allocate(void)
{
int num = 0 ;
char buffer[1000];
FILE *file;
file = fopen("D://bank.txt","r");
if (file == NULL) {
fprintf(stderr, "Unable to open file in allocate()\n");
exit(EXIT_FAILURE);
}
while (fgets(buffer, sizeof(buffer), file) != NULL &&
buffer[0] != '\n') {
num++;
}
acc = malloc(num * sizeof(*acc));
if (acc == NULL) {
fprintf(stderr, "Allocation error in allocate()\n");
exit(EXIT_FAILURE);
}
if (fclose(file) != 0) {
fprintf(stderr, "Unable to close file in allocate()\n");
exit(EXIT_FAILURE);
}
printf(" num in allocate function : %d\n",num);
return num;
}
int loadfile(void)
{
int num = allocate();
char buffer[1000], tempname[20],tempbranch[10];
int tempid ,tempbalance;
if ( num != 0 ) {
int i = 0 ;
FILE *file;
file = fopen("D://bank.txt","r+");
if (file == NULL) {
fprintf(stderr, "Unable to open file in loadfile()\n");
exit(EXIT_FAILURE);
}
while (fgets(buffer, sizeof(buffer), file) != NULL
&& buffer[0] != '\n') {
if (sscanf(buffer, "%19s %d %d %9s",
tempname, &tempid, &tempbalance, tempbranch) != 4) {
fprintf(stderr, "%d: Malformed input data\n", i);
exit(EXIT_FAILURE);
}
strcpy(acc[i].name, tempname);
acc[i].id = tempid;
acc[i].balance = tempbalance;
strcpy(acc[i].branch, tempbranch);
++i;
}
if (fclose(file) != 0) {
fprintf(stderr, "Unable to open file in loadfile()\n");
exit(EXIT_FAILURE);
}
}
return num;
}
int main(void)
{
int num = loadfile();
for (int i = 0; i < num; i++) {
printf("%s %d %d %s\n",
acc[i].name, acc[i].id, acc[i].balance, acc[i].branch);
}
return 0;
}
I can't explain all your problems. It will take me hours. I hope this code will be self-describing. Ask me in a comment if you need some help.
#include <stdlib.h>
#include <stdio.h>
typedef struct {
char name[20];
int id;
int balance;
char branch[10];
} account_t;
static account_t *parse_account_file(FILE *file, size_t *size) {
if (file == NULL || size == NULL) {
return NULL;
}
size_t i = 0;
account_t *account = malloc(sizeof *account);
if (account == NULL) {
return NULL;
}
int ret;
while (
(ret = fscanf(file, "%19s %d %d %9s\n", account[i].name, &account[i].id,
&account[i].balance, account[i].branch)) == 4) {
account_t *old = account;
account = realloc(account, sizeof *account * (++i + 1));
if (account == NULL) {
free(old);
return NULL;
}
}
if (ret == EOF) {
if (ferror(file)) {
perror("parse_account_file()");
} else {
*size = i;
account_t *old = account;
account = realloc(account, sizeof *account * i);
if (account == NULL) {
return old;
}
return account;
}
} else {
fprintf(stderr, "error parsing\n");
}
free(account);
return NULL;
}
int main(void) {
char const *name = "D:\\bank.txt";
FILE *file = stdin;
size_t size;
account_t *account = parse_account_file(file, &size);
fclose(file);
if (account == NULL) {
return 1;
}
for (size_t i = 0; i < size; i++) {
printf("%s %d %d %s\n", account[i].name, account[i].id, account[i].balance,
account[i].branch);
}
free(account);
}
I am novice to C programming and I have written a code to a requirement specification but I am consistently getting Segmentation Fault and unable to proceed ahead.
If the file name is 'code.c' and it runs with an error of not passing the argument (filename). But if the filename is passed, we land in Segmentation Fault.
Any help/suggestions will be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
struct _data
{
char *firstName;
char *lastName;
long number;
};
// SCAN FILE
int SCAN(FILE *(*stream))
{
*stream = fopen("inputFile.data", "r");
int ch = 0, lines = 0;
while (!feof(*stream))
{
ch = fgetc(*stream);
if (ch == '\n')
{
lines++;
}
}
return lines;
}
// LOAD FILE
struct _data *LOAD(FILE *stream, int size)
{
int i;
size_t chrCount;
char *text, *number, *firstName, *lastName;
struct _data *BlackBox;
if ((BlackBox = (struct _data*)calloc(size, sizeof(struct _data))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
rewind(stream);
for (i = 0; i < size; i++)
{
getline(&text, &chrCount, stream);
firstName = strtok(text, " ");
lastName = strtok(text, " ");
number = strtok(NULL, "\n");
// Allocate memory for name part of struct.
if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName), sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName), sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
strcpy(BlackBox[i].firstName, firstName);
strcpy(BlackBox[i].lastName, lastName);
BlackBox[i].number = atol(number);
}
fclose(stream);
return BlackBox;
}
void SEARCH(struct _data *BlackBox, char *name, int size, int inputs)
{
int i;
int found = 0;
char *search = " ";
char *firstName;
char *lastName;
if (inputs == 2)
{
firstName = strtok(name, search);
lastName = strtok(NULL, search);
}
printf("*******************************************\n");
if (inputs == 2)
{
for (i = 0; i < size; i++)
{
if (!strcasecmp(firstName, BlackBox[i].firstName) && !strcasecmp(firstName, BlackBox[i].firstName))
{
printf("The name was found at the %d entry.\n", i);
found = 1;
break;
}
}
}
else
{
for (i = 0; i < size; i++)
{
if (!strcasecmp(firstName, BlackBox[i].firstName) || !strcasecmp(firstName, BlackBox[i].firstName))
{
printf("The name was found at the %d entry.\n", i);
found = 1;
break;
}
}
}
if (found == 0)
{
printf("The name was NOT found.\n");
}
printf("*******************************************\n");
}
// FREE MEMORY
void FREE(struct _data *BlackBox, int size)
{
int i;
for (i = 0; i < size; i++)
{
free(BlackBox[i].firstName);
free(BlackBox[i].lastName);
}
free(BlackBox);
BlackBox = NULL;
}
// MAIN
int main(int argv, char **argc)
{
int size;
FILE *stream;
struct _data *BlackBox;
// argv == 1 WORKS, Below message is printed.
if (argv == 1)
{
printf("*******************************************\n");
printf("* You must include a name to search for. *\n");
printf("*******************************************\n");
}
// argv == 2 DOES NOT WORK, Segmentation Fault.
if (argv == 2)
{
size = SCAN (&stream);
BlackBox = LOAD(stream, size);
SEARCH(BlackBox, argc[1], size, 1);
}
if (argv == 3)
{
size = SCAN(&stream);
BlackBox = LOAD(stream, size);
SEARCH(BlackBox, argc[2], size, 2);
}
return 0;
}
You have a problem in this code:
firstName = strtok(text, " ");
lastName = strtok(text, " ");
number = strtok(NULL, "\n");
...
BlackBox[i].number = atol(number);
The second strtok() call should pass NULL as its first argument. As it is, the third strtok() call is certain to return NULL because the first call modifies text in such a way that the second consumes the whole thing (when tokenizing again from the beginning, as it erroneously does). You do not test for that, however, and as a result, atol() attempts to dereference a null pointer.
Update:
Additionally, as #chqrlie and later #JamesWilkins observed, you do not allocate sufficient space for BlackBox[i].firstName and BlackBox[i].lastName, as you need room for the string terminators as well. This is an entirely separate problem that could also produce a segfault. I like #chqrlie's suggestion to switch to strdup(), but it would be sufficient to just increase each allocation by one unit.
Update 2:
Furthermore, you have an issue with this line:
getline(&text, &chrCount, stream);
You do not initialize variable text before the first call, so it contains a junk value. The function allocates a buffer only when its first argument points to a NULL pointer; otherwise it writes the line to the buffer pointed to by the pointer obtained by dereferencing the first argument. Writing to a random location in memory certainly produces undefined behavior, which in practice often manifests as a segfault.
Moreover, unless you can rely on no line of the file being longer than the first, you also need to free the text pointer at the end of each loop iteration AND reset its value to NULL, so that getline() allocates a fresh buffer on the next iteration. If you do not free it on each iteration, then you need instead to free it after the end of the loop; else you will leak memory.
Try this (though I'm using Visual Studio on Windows). I added code to check for a missing '\n' on the last line, and also allowed for a variable number of search terms. I also increased the memory allocation for strings by 1 to account for the null terminating character. I noticed you are using getline(const char*..., which I think is GNU (Linux?), so I change that to fgets() just so I could compile and test it in VS (so you can change it back if you like). I put in various null checks as well, to be safer.
#include <iostream>
using namespace std;
struct _data
{
char *firstName;
char *lastName;
long number;
};
// SCAN FILE
int SCAN(FILE *(*stream))
{
*stream = fopen("inputFile.data", "r");
if (*stream == NULL)
{
perror("Error opening file");
return 0;
}
char ch = 0, lines = 0, linesize = 0;
while ((ch = fgetc(*stream)) != EOF)
{
if (ch == '\n')
{
lines++;
linesize = 0;
}
else linesize++;
}
if (linesize > 0)
lines++; // (last line doesn't have '\n')
return lines;
}
// LOAD FILE
struct _data *LOAD(FILE *stream, int lineCount)
{
int i;
size_t chrCount = 256;
char text[256], *result, *number, *firstName, *lastName;
struct _data *BlackBox;
if ((BlackBox = (struct _data*)calloc(lineCount, sizeof(struct _data))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
else memset(BlackBox, 0, sizeof(struct _data) * lineCount); // (make sure all data members are null to begin)
rewind(stream);
for (i = 0; i < lineCount; i++)
{
result = fgets(text, chrCount, stream);
if (result == NULL)
break; // (EOF)
firstName = strtok(text, " ");
lastName = strtok(NULL, " ");
number = strtok(NULL, "\n");
// Allocate memory for name part of struct.
if ((BlackBox[i].firstName = (char*)calloc(strlen(firstName) + 1, sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
if ((BlackBox[i].lastName = (char*)calloc(strlen(lastName) + 1, sizeof(char))) == NULL)
{
printf("ERROR - Could not allocate memory.\n");
exit(0);
}
strcpy(BlackBox[i].firstName, firstName);
strcpy(BlackBox[i].lastName, lastName);
BlackBox[i].number = atol(number);
}
fclose(stream);
return BlackBox;
}
void SEARCH(struct _data *BlackBox, char **names, int lineCount, int inputs)
{
int i, l;
int found = 0;
printf("*******************************************\n");
for (i = 0; i < inputs; ++i)
{
for (l = 0; l < lineCount; ++l)
{
if (BlackBox[l].firstName != NULL && !_stricmp(names[i], BlackBox[l].firstName)
|| BlackBox[l].lastName != NULL && !_stricmp(names[i], BlackBox[l].lastName))
{
printf("The name was found on line %d.\n", 1 + l);
found = 1;
break;
}
}
if (found) break;
}
if (!found)
printf("The name was NOT found.\n");
printf("*******************************************\n");
}
// FREE MEMORY
void FREE(struct _data *BlackBox, int lineCount)
{
int i;
for (i = 0; i < lineCount; i++)
{
if (BlackBox[i].firstName != NULL)
free(BlackBox[i].firstName);
if (BlackBox[i].lastName != NULL)
free(BlackBox[i].lastName);
}
free(BlackBox);
}
// MAIN
int main(int argc, char **argv)
{
int lineCount;
FILE *stream;
struct _data *BlackBox;
// argc == 1 WORKS, Below message is printed.
if (argc == 1)
{
printf("*******************************************\n");
printf("* You must include a name to search for. *\n");
printf("*******************************************\n");
}
// argc == 2 DOES NOT WORK, Segmentation Fault.
if (argc > 1)
{
lineCount = SCAN(&stream);
if (lineCount > 0)
{
BlackBox = LOAD(stream, lineCount);
SEARCH(BlackBox, argv + 1, lineCount, argc - 1);
FREE(BlackBox, lineCount);
}
}
return 0;
}
Tested it on the command line, and it works.
The problem is the argv and argc. argc is supposed to be an int (think argument count), while argv is meant to be char**. You have them mixed up in your main.
Can someone help me making a queue program. I want to set the array[0] to be array[1] just in display but in real I am adding value at array[0]. I got how to run the add function to it, but I can't do the view and delete command that will view from ex. array[0] to array[4], when displayed array[1] to array[5] with the value inserted.
#include <stdio.h>
#include <stdlib.h>
#define p printf
#define s scanf
int rear = 0;
int front = 0;
int *q_array = NULL;
int size = 0;
main()
{
int num, opt;
char cont[] = { 'y' };
clrscr();
p("Queue Program\n\n");
p("Queue size: ");
s("%d", &size);
p("\n");
if(size > 0)
{
q_array = malloc(size * sizeof(int));
if(q_array == NULL)
{
p("ERROR: malloc() failed\n");
exit(2);
}
}
else
{
p("ERROR: size should be positive integer\n");
exit(1);
}
while((cont[0] == 'y') || (cont[0] == 'Y'))
{
clrscr();
p("Queue Program");
p("\n\nQueue size: %d\n\n", size);
p("MAIN MENU\n1. Add\n2. Delete\n3. View");
p("\n\nYour choice: ");
s("%d", &opt);
p("\n");
switch(opt) {
case 1:
if(rear==size)
{
p("You can't add more data");
}
else
{
p("Enter data for Queue[%d]: ", rear+1);
s("%d", &num);
add(num);
}
break;
case 2:
delt();
break;
case 3:
view();
break;
}
p("\n\nDo you want to continue? (Y\/N)");
s("%s", &cont[0]);
}
}
add(int a)
{
q_array[rear]=a;
rear++;
}
delt()
{
if(front==rear)
{
p("Queue Empty");
}
else
{
p("Queue[%d] = %d removed.", front, q_array[front]);
front++;
}
}
view()
{
int i;
for(i=front;i<=rear;i++)
p("\nQueue[%d] = %d", i, q_array[i]);
}
One serious problem here is
char cont[] = { 'y' };
...
s("%s", &cont[0]);
You've only reserved one byte but scanf will write at least 2 bytes, meaning that you are going to have a buffer overflow and then the overall behaviour is unpredictable. If you want to read a single character then use"%c" as a pattern but the problem here is that characters will be in the buffer for the next read, so you are going to have to clear the buffer.
It's much easier to do:
char line[1024];
fgets(line, sizeof line, stdin);
if(line[strlen(line)-1] == '\n')
line[strlen(line)-1] = 0;
if(strcmp(line, "Y") == 0 || strcmp(line, "y")==0)
It's a little more code but it's safer this way.
There are many queues, there are fifo, lifo, and depending on it you choose how to build it
When dealing with queues, it's better to use function names like push, pop and top because they are widely used among other programmers and queue libraries. Use
these names instead.
In your case, instead if remembering with front and rear you should use
memmove instead and use a variable len to count the current number of
elements in the node. Once you've popped one element, you gained new space for
more elements.
Also, try to use fewer global variables and more encapsulation: (in my example I am
not going to care about malloc returning NULL, I want to keep it short)
#include <string.h> /* for size_t */
typefed struct {
size_z len;
size_z max_size;
int *data;
} queue;
void queue_init(queue *q, size_t max_size)
{
q->len = 0;
q->max_size = max_size;
q->data = malloc(max_size * sizeof *(q->data));
/* this is a good trick!
* If you need to change the datatype of 'data',
* you only need to change the definition of it.
* This code is valid for any type */
}
int push(queue *q, int data)
{
if(q->len == q->max_size)
return 0; /* not enough space */
q->data[q->len++] = data;
return 1;
}
int top(queue *q, int *data)
{
if(q->len == 0)
return 0; /* no elements in the queue */
*data = q->data[0];
return 1;
}
int pop(queue *q, int *data)
{
if(top(q, data) == 0)
return 0;
memmove(q->data, q->data + sizeof *(q->data), q->len--);
return 1;
}
BTW:
#define p printf
#define s scanf
Just like Daniel Fischer said, this is ugly; don't do that.