I have this four files,
tinyll.c tinyll.h in /home/user/lib
test.c tinyll.h in /home/user/code
and compile with this instructions for create a static library
libtinyll.a and use it.
; in lib
$ gcc -c tinyll.c
$ ar -cvq libtinyll.a *.o
; in code
$ gcc -o test test.c ../lib/libtinyll.a
Until here all is ok. But I don't know why I obtain segmentation fault because the lines from [CODE ERROR] but showElements work. The target is not pass code from test.c to tinyll.c for treat the tiny list linked. How fix that?
/////////////////////////////////// test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
int main(int argc, char *argv[])
{
progname = argv[0];
char *file = "fwords";
int n;
PTLL lsone = NULL;
n = loadfileinTLL(file,&lsone);
// work. good.
showElements(lsone);
// [CODE ERROR]
// Why here dont work?
// segmentation fault, load the first word
// but in the second crash.
while (lsone != NULL) {
printf("%s",lsone->word);
lsone = lsone->next;
}
return 0;
}
/////////////////////////////////// tinyll.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
void addElement(PPTLL lst, char data[])
{
PTLL elemt;
elemt = (PTLL) malloc(sizeof(TLL));
if (elemt == NULL) {
fprintf(stderr, "%s: insufficient memory.\n", progname);
exit(1);
}
if (*lst == NULL)
{
strncpy(elemt->word, data, 45);
elemt->next = NULL;
*lst = elemt;
}
else {
// add in front of list
strncpy(elemt->word, data, 45);
elemt->next = *lst;
*lst = elemt;
}
}
void showElements(PTLL lst)
{
while (lst != NULL) {
printf("%s\n",lst->word);
lst = lst->next;
}
}
int loadfileinTLL(char *filepath, PPTLL plst)
{
FILE *f;
if ((f = fopen(filepath, "r")) == NULL) {
fprintf(stderr, "%s: error to load file %s.\n", progname, filepath);
exit(1);
}
char buf[45]; int n=0;
while (fgets(buf,sizeof(buf),f) != NULL) {
char *nl;
if ((nl = strchr(buf,'\n')) != NULL) {
*nl = '\0';
}
addElement(plst,buf);
n++;
}
fclose(f);
return n;
}
//////////////////////////////////// tinyll.h
#include <stdio.h>
#include <stdlib.h>
#ifndef _TINYLL_
#define _TINYLL_
struct list {
char word[45];
struct list *next;
};
// Tiny Linked List
typedef struct list TLL;
typedef struct list *PTLL;
typedef struct list **PPTLL;
char *progname;
#endif
the following code:
1) compiles cleanly
2) performs correctly, with out seg faulting.
3) checks and handles errors correctly
4) cleans up after itself, by freeing any allocated memory
5) removed leading underscores from names
as leading underscores has special meaning to the compiler
tinyll.h
#ifndef TINYLL_
#define TINYLL_
struct list
{
char word[45];
struct list *next;
};
// Tiny Linked List
typedef struct list TLL;
typedef struct list *PTLL;
typedef struct list **PPTLL;
extern char *progname;
void addElement(PPTLL lst, char data[]);
void showElements(PTLL lst);
int loadfileinTLL(char *filepath, PPTLL plst);
#endif // TINYLL_
tinyll.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
void addElement(PPTLL lst, char data[])
{
PTLL elemt;
elemt = (PTLL) malloc(sizeof(TLL));
if (elemt == NULL) {
fprintf(stderr, "%s: insufficient memory.\n", progname);
exit(1);
}
if (*lst == NULL)
{
strncpy(elemt->word, data, 45);
elemt->next = NULL;
*lst = elemt;
}
else {
// add in front of list
strncpy(elemt->word, data, 45);
elemt->next = *lst;
*lst = elemt;
}
}
void showElements(PTLL lst)
{
while (lst != NULL) {
printf("%s\n",lst->word);
lst = lst->next;
}
}
int loadfileinTLL(char *filepath, PPTLL plst)
{
int n=0;
FILE *f;
if ((f = fopen(filepath, "r")) == NULL)
{
fprintf(stderr, "%s: error to load file %s.\n", progname, filepath);
n = -1;
}
else
{
char buf[45];
while (fgets(buf,sizeof(buf),f) != NULL)
{
char *nl;
if ((nl = strchr(buf,'\n')) != NULL)
{
*nl = '\0';
}
addElement(plst,buf);
n++;
}
fclose(f);
} // endif
return n;
}
test.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "tinyll.h"
char *progname;
int main(int argc, char *argv[])
{
if( 1 == argc )
{
progname = argv[0];
}
else
{
printf( "USAGE: %s\n", argv[0]);
exit( EXIT_FAILURE );
}
// implied else, right number (0) of arguments on command line
char *file = "fwords";
int n;
PTLL lsone = NULL;
PTLL lstwo = NULL;
n = loadfileinTLL(file,&lsone);
if( n > 0 )
{
// work. good.
showElements(lsone);
// [CODE ERROR]
// Why here dont work?
// segmentation fault, load the first word
// but in the second crash.
lstwo = lsone;
while (lstwo)
{
printf("%s",lstwo->word);
lstwo = lstwo->next;
}
} // endif
while( lsone )
{
lstwo = lsone->next;
free(lsone);
lsone = lstwo;
} // end while
return 0;
}
I used the following for a test file:
one
two
three
four
five
six
and the output was:
six
five
four
three
two
one
sixfivefourthreetwoone
Related
I am trying to write a program that implements somehow the "dir" command that you can use in the Unix shell but I have encountered the following problem. I managed to read the current directory as I will show in the code but I don't know exactly how I am supposed to sort it in order to make it like the dir function which sorts the files from the directory
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
void dirfunction()
{
DIR* directory=opendir(".");
if(directory==NULL)
{
perror("Directory does not exist");
exit(1);
}
struct dirent* p;
p=readdir(directory);
int i=0;
while(p!=NULL)
{
if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)
{
printf("%s ",p->d_name);
i++;
}
p=readdir(directory);
}
printf("\n");
closedir(directory);
}
int main(int argc,char** argv[])
{
dirfunction();
}
Should I basically do the normal sorting for an array of character, like adding all file names in an array of string and sort it with selection sort or another sort method? I don't really get how dir command sorts the files before printing them to the terminal.
Because readdir reuses the same buffer for the returned entry, we need a dynamic [growing] array to save/store the struct dirent entries.
Then, we need to sort the stored entries (e.g. use qsort).
Side note: int main(int argc,char **argv[]) is incorrect. It should be: int main(int argc,char **argv) There was one too many levels of indirection.
Below is the updated code with some enhancements. It is annotated:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
// dynamic array of dirent structs
struct dirlist {
size_t count; // number of entries
struct dirent *base; // pointer to list start
};
// dirload -- load up directory
// RETURNS: directory list
struct dirlist *
dirload(const char *path)
{
size_t capacity = 0;
struct dirlist *list = calloc(1,sizeof(*list));
DIR *directory = opendir(path);
if (directory == NULL) {
perror("Directory does not exist");
exit(1);
}
struct dirent *p;
while (1) {
// get next entry
// this is overwritten, so we need to copy/save it below
p = readdir(directory);
if (p == NULL)
break;
// skip over "." and ".."
if (p->d_name[0] == '.') {
if (p->d_name[1] == 0)
continue;
if ((p->d_name[1] == '.') && (p->d_name[2] == 0))
continue;
}
// enlarge array
if (list->count >= capacity) {
capacity += 10;
list->base = realloc(list->base,sizeof(*list->base) * capacity);
if (list->base == NULL) {
perror("realloc");
exit(1);
}
}
// save dirent entry
list->base[list->count++] = *p;
}
closedir(directory);
// trim list to actual size
list->base = realloc(list->base,sizeof(*list->base) * list->count);
if (list->base == NULL) {
perror("realloc");
exit(1);
}
return list;
}
// dircmp -- compare dirent structs
int
dircmp(const void *lhsp,const void *rhsp)
{
const struct dirent *lhs = lhsp;
const struct dirent *rhs = rhsp;
int cmp;
cmp = strcmp(lhs->d_name,rhs->d_name);
return cmp;
}
// dirsort -- sort directory list
void
dirsort(struct dirlist *list)
{
if (list->count > 0)
qsort(list->base,list->count,sizeof(*list->base),dircmp);
}
// dirprint -- print directory list
void
dirprint(const struct dirlist *list)
{
const struct dirent *p = list->base;
for (size_t idx = 0; idx < list->count; ++idx, ++p)
printf("%s\n",p->d_name);
}
// dirdestroy -- destroy directory list
void
dirdestroy(struct dirlist *list)
{
if (list != NULL)
free(list->base);
free(list);
}
int
main(int argc, char **argv)
{
--argc;
++argv;
const char *dir;
if (argc > 0)
dir = *argv;
else
dir = ".";
struct dirlist *list = dirload(dir);
// sort the list
dirsort(list);
// print the list
dirprint(list);
// destroy the list
dirdestroy(list);
return 0;
}
I am creating a struct called Job and I want to create an array of struct Job. The name of my array is jobQueue I populate the array using commandline args. The instructor has it set up to where **args is being used. After the user inputs the name of the job and the execution time it gets added to the array. However, when I try to print jobQueue[0].name using the list() funct I have written, the name does not get printed. I'm trying to get my code set up to where I can print the name. I have provided a minimal version of my overall project that just focuses on the specific problem I am encountering and should compile and run fine.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <assert.h>
#include <sys/wait.h>
#include <stdint.h>
#define EINVAL 1
#define E2BIG 2
#define MAXMENUARGS 7
//structure job initialize
struct Job {
//initializing name variable
char *name;
int executionTime;
};
//init the array
struct Job jobQueue[5] = {0};
//cmd function provided by intructor
int cmd_run(int nargs, char **args) {
int execT;
sscanf(args[2], "%d", &execT);
run(args[1], execT);
return 0;
}
//cmd function provided by intructor
void cmd_list() {
list();
}
//cmd function provided by intructor
static struct {
const char *name;
int (*func)(int nargs, char **args);
} cmdtable[] = {
/* commands: single command must end with \n */
{ "r", cmd_run},
{ "run", cmd_run},
{ "list\n", cmd_list}
};
//cmd function provided by intructor
//this is the function that handles the arguments entered by the user
//provided it just in case someone needs to see how arguments are being
//processed
int cmd_dispatch(char *cmd) {
time_t beforesecs, aftersecs, secs;
u_int32_t beforensecs, afternsecs, nsecs;
char *args[MAXMENUARGS];
int nargs = 0;
char *word;
char *context;
int i, result;
void *Dispatcher(void *arg);
for (word = strtok_r(cmd, " ", &context);
word != NULL;
word = strtok_r(NULL, " ", &context)) {
if (nargs >= MAXMENUARGS) {
printf("Command line has too many words\n");
return E2BIG;
}
args[nargs++] = word;
}
if (nargs == 0) {
return 0;
}
for (i = 0; cmdtable[i].name; i++) {
if (*cmdtable[i].name && !strcmp(args[0], cmdtable[i].name)) {
assert(cmdtable[i].func != NULL);
/* Call function through the cmd_table */
result = cmdtable[i].func(nargs, args);
return result;
}
}
printf("%s: Command not found\n", args[0]);
return EINVAL;
}
//adds job to the array using user arguments
void run(char name[], int executionTime) {
//creates a job using the arguments specified by user
struct Job job = {name, executionTime};
jobQueue[0] = job;
printf("\nJob added to queue now please type 'list'\n");
}
//name will not print here
void list() {
printf("\nSee how the name will not print below?\n");
char executionTimeStr[5];
for (int c = 0; c < sizeof (jobQueue) / sizeof (jobQueue[0]); c++) {
//prints job info formatted
if (jobQueue[c].name != NULL) {
sprintf(executionTimeStr, "%d", jobQueue[c].executionTime);
//job name will not print here, output is just left blank
printf("%s %20.8s", "Name", "ExecTime");
printf("%-10.15s %11.3s\n",
jobQueue[c].name,
executionTimeStr
);
}
}
}
int main(int argc, char *argv[]) {
printf("Welcome to our batch job scheduler\n");
printf("Please enter the following exactly: 'run job1 10' \n");
//ignore this, it handles my commandline parser
char *buffer;
size_t bufsize = 64;
buffer = (char*) malloc(bufsize * sizeof (char));
if (buffer == NULL) {
perror("Unable to malloc buffer");
exit(1);
}
while (1) {
printf("User Input: ");
getline(&buffer, &bufsize, stdin);
cmd_dispatch(buffer);
}
//ignore this, it handles my commandline parser
return 0;
}
have to write a program displaying list of all logged users (their id and groups if -i or -g is used) using shared library. The functions in shared library are working correctly, but it seems like function pointer causes segmentation fault. Since it's a school assigment I have to use C and functions have to return nothing, and take only user name. I'm quite new to programming in linux (obviously).
main code:
#include <unistd.h>
#include <stdlib.h>
#include <utmp.h>
#include <dlfcn.h>
struct utmp *p;
int main(int argc, char* argv[]){
int opt, iflag = 0;
int gflag = 0;
void *handle;
while((opt = getopt(argc, argv, "ig")) != -1)
{
switch(opt)
{
case 'i':
iflag = 1;
break;
case 'g':
gflag = 1;
break;
default:
fprintf(stderr, "Błąd \n");
exit(EXIT_FAILURE);
}
}
handle = dlopen("./zad2lib.so", RTLD_LAZY);
if (handle == NULL) {
fprintf(stderr, "Unable to open library: %s\n", dlerror());
iflag = 0;
gflag = 0;
}
while ((p = getutent()) != NULL) {
if (p->ut_type == USER_PROCESS)
{
if (iflag == 1) {
dlerror();
void (*func)(char*) = (void(*)())dlsym(handle, "userID");
func(p->ut_user);
}
printf("%s ", p->ut_user);
if (gflag == 1) {
dlerror();
void (*func)(char*) = (void(*)())dlsym(handle, "userGroups");
func(p->ut_user);
}
}
printf("\n");
}
dlclose(handle);
}
return 0;
}
.so file:
#include <sys/types.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
void userID(char *name) {
struct passwd *pw = getpwnam(name);
printf("%d ", pw->pw_uid);
}
void userGroups(char *name) {
struct passwd *pw = getpwnam(name);
int i;
int gidsize = 100;
struct group* g;
gid_t *grouplist = malloc(gidsize*sizeof(gid_t));
getgrouplist(name, pw->pw_gid, grouplist, &gidsize);
printf("[");
for (i = 0; i < gidsize; i++) {
g = getgrgid(grouplist[i]);
printf(" %s", g->gr_name);
}
printf(" ]");
free(grouplist);
}
I have this code which will print to the console all files in a given folder which have a given extension:
int scandir(char dirname[], char const *ext)
/* Scans a directory and retrieves all files of given extension */
{
DIR *d = NULL;
struct dirent *dir = NULL;
d = opendir(dirname);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (has_extension(dir->d_name, ext))
{
printf("%s\n", dir->d_name);
}
}
closedir(d);
}
return(0);
}
This function works, but I would like to modify it so that it returns an array of filenames.
(I have done a lot of google searches but only come up with functions like mine, which print to console)
I'm fairly new to C and 'low-level' programming, so I am unsure of how to correctly handle the memory here.
How do I create and add things to a character array when I do not know how big it is going to be?
I'm using MinGW..
You can use realloc:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
extern char *strdup(const char *src);
int scandir(char ***list, char dirname[], char const *ext)
/* Scans a directory and retrieves all files of given extension */
{
DIR *d = NULL;
struct dirent *dir = NULL;
size_t n = 0;
d = opendir(dirname);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (has_extension(dir->d_name, ext))
{
*list = realloc(*list, sizeof(**list) * (n + 1));
(*list)[n++] = strdup(dir->d_name);
}
}
closedir(d);
}
return n;
}
int main(void)
{
char **list = NULL;
size_t i, n = scandir(&list, "/your/path", "jpg");
for (i = 0; i < n; i++) {
printf("%s\n", list[i]);
free(list[i]);
}
free(list);
return 0;
}
Note that strdup() is not a standard function but its available on many implementations.
As an alternative to realloc you can use a singly linked list of strings.
EDIT: As pointed out by #2501, is better to return an allocated array of strings from scandir and pass elems as param:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
extern char *strdup(const char *src);
char **scandir(char dirname[], char const *ext, size_t *elems)
/* Scans a directory and retrieves all files of given extension */
{
DIR *d = NULL;
struct dirent *dir = NULL;
char **list = NULL;
d = opendir(dirname);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (has_extension(dir->d_name, ext))
{
list = realloc(list, sizeof(*list) * (*elems + 1));
list[(*elems)++] = strdup(dir->d_name);
}
}
closedir(d);
}
return list;
}
int main(void)
{
size_t i, n = 0;
char **list = scandir("/your/path", "jpg", &n);
for (i = 0; i < n; i++) {
printf("%s\n", list[i]);
free(list[i]);
}
free(list);
return 0;
}
Finally, do you really need an array? Consider using a call-back function:
#include <stdio.h>
#include <string.h>
#include <dirent.h>
void cb_scandir(const char *src)
{
/* do whatever you want with the passed dir */
printf("%s\n", src);
}
int scandir(char dirname[], char const *ext, void (*callback)(const char *))
/* Scans a directory and retrieves all files of given extension */
{
DIR *d = NULL;
struct dirent *dir = NULL;
size_t n = 0;
d = opendir(dirname);
if (d)
{
while ((dir = readdir(d)) != NULL)
{
if (has_extension(dir->d_name, ext))
{
callback(dir->d_name);
n++;
}
}
closedir(d);
}
return n;
}
int main(void)
{
scandir("/your/path", "jpg", cb_scandir);
return 0;
}
Can anyone give me some indication as to why array of structs doesn't print out properly ?
I think its something to do with the memory I have allocated to the struct I am unsure !!
Using mac osx mountain lion xcode 4 gcc
Thanks for any help completely stuck!!
(Please have patience I am only a student !)
#include <stdio.h>
#include <limits.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
typedef struct{
char* one;
char* two;
} Node;
Node *nodes;
int count = 0;
//-----------------------------------------------------------------------
void add(char *one,char*two){
char x[40];
char y[40];
printf("reached..\n");
strcpy(x,one);
strcpy(y,two);
printf("--> X: %s\n",x);
printf("--> Y: %s\n",y);
Node newNode;
newNode.one = x;
newNode.two = y;
nodes[count]= newNode;
count++;
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void print(){
int x;
for (x = 0; x < 10; x++)
{
printf("%d : (%s, %s) \n",x,nodes[x].one, nodes[x].two);
}
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
void check(char **arg)
{
if(strcmp(*arg, "Add") == 0)
{
add(arg[1],arg[2]);
}else if(strcmp(*arg,"print") == 0)
{
print();
}else{
printf("Error syntax Enter either: \n Add [item1][item2]\n OR \n print\n");
}
}
//-----------------------------------------------------------------------
void readandParseInput(char *line,char **arg)
{
if (fgets (line, 512, stdin)!= NULL) {
char * pch;
pch = strtok (line," \n\t");
int count = 0;
arg[0] = pch;
while (pch != NULL)
{
count++;
pch = strtok (NULL, " \n\t");
arg[count] =pch;
}
}else{
printf("\n");
exit(0);
}
}
//-----------------------------------------------------------------------
int main()
{
int size = 100;
nodes = calloc(size, sizeof(Node));
int i;
for(i = 0;i <100; i++){
printf("%s , %s \n",nodes[i].one,nodes[i].two );
// nodes[i].one = ".";
// nodes[i].two = ".";
}
char line[512]; /* the input line */
char *arg[50]; /* the command line argument */
while (1)
{
readandParseInput(line,arg);
if(arg[0] != NULL){
check(arg);
}
}
return(0);
}
You're keeping pointers to the following automatic variables:
char x[40];
char y[40];
These go out of scope when add() returns, leaving you with dangling pointers.
You either have to turn Node::one and Node::two into arrays, or allocate memory for them on the heap.
In you add() function, you cannot assign one struct to another via an = operator... you would have to copy it...
memcpy( &nodes[count], &newNode )
#include <stdio.h>
#include <stdlib.h>
typedef struct {
char *fn;
}NAME;
#define NAME_LEN 20
int main()
{
NAME name;
name.fn = (char *) calloc(NAME_LEN, sizeof(char));
strcpy(name.fn, "Namco");
printf("Name: %s\n", name.fn);
free(name.fn);
return 0;
}
you can't just assign a string like this in c
newNode.one = x;
newNode.two = y;
what is newNode.one referring to???
at Function add
newNode.one = x;
newNode.two = y;
to
newNode.one = strdup(x);
newNode.two = strdup(y);