#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
typedef struct {
char name[128], code[128];
} info;
info db[3];
info* data=db;
void find (const char *code, int size, ...) {
bool mismatch = true;
va_list arg;
va_start(arg,size);
while (size-- > 0) {
data = va_arg(arg,info*);
printf("%s", data->code);
if (!strcmp(data->code,code))
{
printf("%s [id:%s]\n",data->name,data->code), mismatch = false;
}
}
if (mismatch) printf("No data available!");
return;
}
int main (int argc, char *argv[], char *envp[]) {
const char *spec[] = {
"Physics of Elementary Particles",
"Physics of Hign Energy",
"Low-level Programming"
};
const char *code[] = {
"2396","0812", "0773"
};`enter code here`
for (int count = 0; count < 3; ++count) {
strncpy(db[count].name,spec[count],128);
strncpy(db[count].code,code[count],128);
}
find("0812",3,db[0],db[1],db[2]);
return 0;
}
After running it says "read access violation", although I hope everything is correct, it happens after function "va_arg(arg, info*)". Is it some troubles with stack or decrypting?
The problem is in the function call:
find("0812",3,db[0],db[1],db[2]);
The variadic argument that you're passing in are of type info. However, when you retrieve them with va_arg you're looking for a info *. These don't match up.
You want to pass in the address of each array member.
find("0812",3,&db[0],&db[1],&db[2]);
Also, you need to call va_end at the bottom of find before you return.
Related
Outside of using a hash function, I'd like to write a basic mapping of a key/value lookup of a few movie-credits related items. Does the following macro seem like an acceptable way to do it?
#include <stdio.h>
#include <string.h>
#define TOMAP(input_str, output_buf, from, to) \
if (strcmp(input_str, from) == 0) \
strcpy(output_buf, to)
void map_imdb_position(const char* pos, char output[])
{
TOMAP(pos, output, "Director", "director");
TOMAP(pos, output, "Writer", "scribe");
}
int main(void) {
char position[20];
map_imdb_position("Director", position);
printf("Director->%s\n", position);
}
If not, what might be a better approach to doing a sort of switch statement on a string comparison?
As suggested in the comments a cleaner way to do this would be with a map of credits in a function, for example:
#include <stdio.h>
#include <string.h>
typedef struct map {
char from[20];
char to[20];
} Map;
void map_imdb_position(const char* credit, char output[])
{
static Map credits[] = {
{"Director", "director"},
{"Writer", "scribe"}
};
for (int i=0; i < sizeof(credits)/sizeof(*credits); i++) {
if (strcmp(credit,credits[i].from) == 0) {
strcpy(output, credits[i].to);
break;
}
}
printf("%s --> %s\n", credit, output);
}
int main(void) {
char position[20];
map_imdb_position("Director", position);
map_imdb_position("Writer", position);
}
Working example: https://onlinegdb.com/Sk_t76aQ_
Side note: I was working on this solution but Carl already came up with a similar one.
But, I prefer to use the ptr->field syntax and to have an end-of-table sentinel at the end (vs. the sizeof construct to get the count).
And, I think designated initializers when constructing the table make things more readable [especially if more fields need to be added to the struct].
So, here's my version:
#include <stdio.h>
#include <string.h>
typedef struct {
const char *from;
const char *to;
} mapimdb_t;
mapimdb_t mapimdb[] = {
{ .from = "Director", .to = "director" },
{ .from = "Writer", .to = "scribe" },
// ...
{ .from = NULL }
};
void
map_imdb_position(const char *pos, char *output)
{
for (const mapimdb_t *map = mapimdb; map->from != NULL; ++map) {
if (strcmp(pos,map->from) == 0) {
strcpy(output,map->to);
break;
}
}
}
void
dotest(const char *from,char *out)
{
map_imdb_position(from,out);
printf("dotest: %s->%s\n",from,out);
}
int
main(void)
{
char position[20];
dotest("Director", position);
dotest("Writer", position);
}
X macros can be used:
#include <stdio.h>
#include <string.h>
#define STR_LIST \
X("Director", "director") \
X("Writer", "scribe")
void map_imdb_position(const char* pos, char output[])
{
#define X(from, to) \
if (strcmp(pos, from) == 0) \
{ strcpy(output, to); return; } // "return" was missing?
STR_LIST
#undef X
}
int main(void) {
char position[20];
map_imdb_position("Director", position);
printf("Director->%s\n", position);
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct kezdo
{
int mennyi;
char betu;
}KEZDO;
int main(int argc, char* argv[])
{
int j;
int i;
int db=0;
int volt=0;
char sajt[22];
FILE* f=fopen(argv[1], "r");
if(f==NULL)
{
fprintf(stderr, "Hiba a fajl megnyitasaban!");
}
int k = 20;
KEZDO t[k];
KEZDO tmp;
for(i=0;i<k;i++)
{
t[i].mennyi = 0;
}
while(fgets(sajt,22,f)!=0)
{
if(sajt[strlen(sajt)-1] == '\n')
{
sajt[strlen(sajt)-1] = '\0';
}
for(i=0;i<k;i++)
{
if(t[i].betu == toupper(sajt[0]))
{
t[i].mennyi++;
volt=1;
}
}
if(volt==0)
{
t[db].betu = toupper(sajt[0]);
t[db].mennyi++;
db++;
}
else
{
volt = 0;
}
}
for(i=0;i<db;i++)
{
printf("%c: %d\n", t[i].betu, t[i].mennyi);
}
return 0;
}
I tried strcmp and stricmp but neither worked. I tried to fully change the struct by sorting the struct properties. When the struct properties are sorted it doesn't work, but it worked before in a non-sorted order. What is preventing output when the struct properties are sorted?
As i can see in your code, you want to sort on char betu. One way to sort structures is via qsort but that'd require comparator function stated below:
int compare(const void *void_a, const void *void_b)
{
const KEZDO *a = void_a;
const KEZDO *b = void_b;
return (a->betu) < (b->betu);
}
//Perform sort like this;
qsort((void *) &t, db, sizeof(KEZDO) , compare );
Moreover, qsort is in #include <stdlib.h>
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;
}
My code is giving me a segmentation fault and I can't seem to find what I'm doing wrong:
#include <stdio.h>
#include <string.h>
char find(char name[], char allNames[][10], int length)
{
int i=0;
for (i = 0; i < length; i++) {
if (strcmp(allNames[i],name) == 1) {
printf("%i",i);
return *name;
}
}
return -1;
}
main(){
char allNames[][10] = {"cat","dog","frog","log","bog"};
char name[] = "log";
int length=5;
printf("%s",find(name,allNames,length));
}
I'm really keen to understand all the mechanisms happening here and what I'm doing wrong for tomorrows exam. Thanks for your help!
EDIT: Really Appreciate the answers and information guys! I'm really quite new to C and just getting used to what every thing means. The particular exam question I am looking at is :
(a) The following function is intended to find the string name in the array
allNames. If found, it returns the position of name in the array. If not
found, it returns -1. Modify the code so that it works correctly.
int find(char name[], char allNames[][10])
{
for (i = 0; i < 10; i++) {
if (allNames[i] == name) {
return name;
}
}
return -1;
}
And I'm trying to get a program to work within these parameters. Cheers :)
http://coliru.stacked-crooked.com/a/d400c9a56d732446
#include <stdio.h>
#include <string.h>
char* find(char name[], char allNames[][10], int length)
{
int i=0;
for (i = 0; i < length; i++) {
if (!strcmp(allNames[i],name)) {
printf("%i",i);
return name;
}
}
return NULL;
}
int main(){
char allNames[][10] = {"cat","dog","frog","log","bog"};
char name[] = "log";
int length=5;
printf("%s",find(name,allNames,length));
}
Returning a single char will do you no good if you're trying to return a string. I would also suggest that you return a NULL if you cannot find the string.
Also, include the int before main; this is better style.
The direct reason for your Segmentation Fault here is because the code tried to print the char type with %s(which needs an address value).
void main()
{
char c = 'a';
printf("%s", c); // will cause Segmentation fault here
}
Back to your code, that is
char find(char name[], char allNames[][10], int length)//return char
printf("%s",find(name,allNames,length));
The minimal change to make it work as follows,
1) To return char*
char* find(char name[], char allNames[][10], int length)//return char*
{
int i=0;
for (i = 0; i < length; i++) {
if (strcmp(allNames[i],name) == 0) { // here should 0
printf("%i",i);
return name; // change name* to name
}
}
return NULL; // change to NULL
}
//to print
printf("%s",find(name,allNames,length));
2) to return position value
int find(char name[], char allNames[][10])
{
for (i = 0; i < 10; i++) {
if (allNames[i] == name) {
return i; // here, change to return i
}
}
return -1;
}
//then, you can print like this
printf("find at position: %d",find(name,allNames,length));
//or to print string by
int pos = find(name,allNames,length);
if(pos >= 0)
printf("find the string: %s",allNames[pos]);
This code is wrong on several levels.
gcc -Wall -Wextra reveals:
meh.c:15:1: warning: return type defaults to ‘int’ [-Wreturn-type]
main(){
^
meh.c: In function ‘main’:
meh.c:19:3: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
printf("%s",find(name,allNames,length));
^
meh.c:21:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
What's up with that? Do you compile with warnings enabled?
I am ignoring the lack of indentation.
#include <stdio.h>
#include <string.h>
char find(char name[], char allNames[][10], int length)
What? How about: char *name, **list, int size)
{
int i=0;
Why set it to 0 here?
for (i = 0; i < length; i++) {
if (strcmp(allNames[i],name) == 1) {
printf("%i",i);
return *name;
Have you read strcmp's manpage? It returns ZERO when a string matches, so this code makes no sense.
*name is of type char, but you don't want to return a char. You want to return a pointer, no?
}
}
return -1;
Well, given that you feed that into %s in printf, what do you expect to hapen here? Normally one would return NULL.
}
main(){
This is obsolete syntax, I don't know where you stole it from. Use 'int main(void)'.
char allNames[][10] = {"cat","dog","frog","log","bog"};
Normally people just return such arrays with a NULL pointer, so that these can be iterated over and there is no need to pass anything about the size.
char name[] = "log";
Why not char *name = "log".
int length=5;
Incorrect. It hardcodes the amount of stored strings in allNames table.
printf("%s",find(name,allNames,length));
}
I have the following code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* user;
char* passwd;
int nr;
void test()
{
int i=0;
for(i=0;i<argc;i++)
printf("Hello %s \n",user);
}
int main(int argc,char*argv[])
{
int i;
nr=argc;
for (i=0; i<argc; i++)
{
user=strdup(argv[i]);
}
test();
return 0;
}
The result is the argv[argc] on all the positions. How can I fix this? I wwant to have that test() outside the loop.
**
EDIT
**
After the ANSWERS here this is my new code, which is not working. Can anyone say why?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* user;
void test(int n)
{
int i=0;
for(i=0;i<n;i++)
printf("%s \n",user[i]);
}
int main(int argc,char*argv[])
{
user = (char*) malloc(argc*sizeof(char));
int i;
for (i=0;i<argc;i++)
{
user[i]=argv[i];
}
test(argc);
return 0;
}
You are assigning to both password and user at each iteration of the for loop. The final values you see are from the last iteration. Also, there is memory leak due to overwriting the pointers from previous strdup calls. In fact, you do not need a loop:
int main(int argc,char*argv[])
{
if(argc == 3) {
user=strdup(argv[1]);
passwd=strdup(argv[2]);
} else {
// error: usage
}
test();
return 0;
}
If you want to have multiple user/password combinations:
char *user[256], *passwd[256];
void test(int n) {
int i;
for(i=0;i<n;i++)
printf("Hello %s \n",user[i]);
}
int main(int argc,char*argv[])
{
int i;
for(i = 0; i < argc && i < 256; i+=2) {
user[i]=strdup(argv[i]);
passwd[i]=strdup(argv[i+1]);
}
test(argc);
return 0;
}
Because you overwrite the pointers user and passwd in every iteration. Hence, you'll only see the last string.
If you can tell your aim of the program, a better answer can be provided. Because I am not sure whether you want to read one user and passwd Or an array of users and passwds.
After you edit, I see you want to read an array of strings:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char** user;
// or char *user[100]; /* If you want a fix length array of pointers. Now, you dont have to malloc. /*
char* passwd;
int nr;
void test(int argc)
{
int i=0;
for(i=0;i<argc;i++)
printf("Hello %s \n",user[i]);
}
int main(int argc,char*argv[])
{
int i;
nr=argc;
user = malloc(argc*sizeof(char*));
for (i=0; i<argc; i++)
{
user[i]=strdup(argv[i]);
}
test(argc);
return 0;
}
Of course; in test() you don't use i other than a loop variable and in main() you keep overwriting the previous value of user and passwd. In effect, what you do is:
user = strdup(argv[0]); /* Note: argv[0] is the program name. */
passwd = strdup(argv[0]);
user = strdup(argv[1]);
passwd = strdup(argv[1]);
user = strdup(argv[2]);
passwd = strdup(argv[2]);
user = strdup(argv[3]);
passwd = strdup(argv[3]);
printf("%s %s \n", user, passwd);
With this information, can you fix your program?
$ cat trash.c
#include <stdio.h>
#include <string.h>
void test(FILE* stream, char* usr, char* pass) {
fprintf( stream, "%s#%s\n", usr, pass);
}
int main(int argc, char** argv) {
int i = 1;
if (argc % 2) {
while(argv[i]) {
test(stdout, argv[i], argv[i + 1]);
i += 2;
}
}
return 0;
}
$ clang trash.c
$ ./a.out user1 pass1 user2 pass2
user1#pass1
user2#pass2
$
also if you call strdup() don't forget to free memory, because strdup called malloc().