Program specifications:
Read questions from a data file in the following format:
Question
Number of choices
N-amount of choices
Correct answer
Example:
What is the capital of France?
3
Madrid
Sydney
Paris
Paris
Present the user a question at a time and keep track of their score, etc, etc.
What I have so far:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_LINE_SIZE 60
#define MAX_LIST_SIZE 15
#define MAX_QUIZ_SIZE 10
typedef struct question {
char *question;
char **choices;
int n_choices;
char *correct_answer;
} QUESTION;
typedef struct quiz {
struct question *questions;
int n_questions;
} QUIZ;
char *dupString(const char *s) {
// copies a string
char *dup = malloc(strlen(s) + 1);
strcpy(dup, s);
return dup;
}
void free_choices(QUESTION *q) {
// free memory
for(int i = 0; i < q->n_choices; i++) {
free(q->choices[i]);
}
free(q->choices);
}
int ask(QUESTION *q) {
// Return 1 for correct guess, 0 for incorrect guess.
int choice;
// Print the question
printf("\n%s\n", q->question);
// Print the choices
for (int i = 0; i <= q->n_choices-1; i++) {
printf("%d : %s", i+1, q->choices[i]);
}
// Get user guess
do {
printf("Select an answer [1-%d]: ", q->n_choices);
scanf("%d", &choice);
/* Not sure how to structure here*/
if (strcmp(q->choices[choice-1], q->correct_answer) == 0) {
// if correct return 1
return 1;
}
} while (choice < 1 || choice > q->n_choices);
// Incorrect
return 0;
}
struct question parseQuestion(FILE *pData) {
int qIndex, numChoices;
char question[MAX_LINE_SIZE], temp[MAX_LINE_SIZE], choices[MAX_LINE_SIZE], correctAns[MAX_LINE_SIZE];
QUESTION q = {NULL, NULL, 0, NULL};
// Eat first line = QUESTION
fgets(question, MAX_LINE_SIZE, pData);
q.question = question;
// Eat second line = NUMBER OF CHOICES
fgets(temp, MAX_LINE_SIZE, pData);
numChoices = atoi(temp);
q.n_choices = numChoices;
// Allocate memory
q.choices = calloc(q.n_choices, sizeof(char*));
// Eat nth lines = CHOICES
for (qIndex=0; qIndex<=numChoices-1; qIndex++) {
fgets(choices, MAX_LINE_SIZE, pData);
q.choices[qIndex] = dupString(choices);
}
// Eat nth + 1 line = CORRECT ANSWER
fgets(correctAns, MAX_LINE_SIZE, pData);
q.correct_answer = correctAns;
return q;
}
int main() {
int num = 0; // question being asked
int strikes = 0; // incorrect guesses
FILE* pData;
char *filename = "tickle.txt";
char c;
if ((pData = fopen(filename, "r"))) {
printf("Welcome to the 2014 Quiz-festival!\n\n");
printf("Are you ready to begin? [Y/y]\n");
c = getchar();
if (c == 'Y' || c == 'y') {
QUESTION question = parseQuestion(pData);
ask(&question);
free_choices(&question);
} else {
printf("Come back again.\n");
return 0;
}
} else {
printf("File failed to open.");
}
fclose(pData);
return 0;
}
Thank you to #alk how picked up my error, that is resolved.
What I still can't get is how to loop through the data file and populate the quiz structure with question structures.
So this is where I'm struggling at the moment. From what I can tell I'm pretty close to finishing this little program as long as I can get this to work.
parseQuestion() duplicates the choices but misses to duplicate the question as well as the answer.
Instead it simply copies the two arrays' addresses to the locally defined variable QUESTION q which is copied on return.
The memory for the question and answer strings is free'd on returning from the function, accessing it afterwards invokes undefined behaviuor.
Related
How can I solve this problem given to us in our lab test? I have tried manier times but failed. I have started learning C since 2 months.
Q:
Read a file named food.txt during execution of your program to store all these items and their respective prices in an array of structure item.
Note: 'struct item' contains 'char name' and 'int price'.
Also, first line of food.txt gives number of entries.
(command: ./a.out < food.txt).
Edit: This is my code. I can't find my mistake.
#include<stdio.h>
//Defining the struct
typedef struct {
char name[25];
int price;
}item;
int main(){
int n; //Number of entries
int i,j,k,flag;
int temp[40];
scanf("%d",&n);//first line gives number of entries as input
item items[n]; //creating our items struct
int c = getchar();
for(i=0;i<n;i++){
items[i].price=0;
for(j=0;;j++){
c=getchar();
if(c<'0' || c>'9') items[i].name[j]=c; //If c is character, it store it in name
if(c=='\n')break; //If c is \n, it breaks from the loop and starts again with i++
temp[j]=c;
}
for(j=0;;j++){
if(temp[j]>=0 && temp[j]<=9){
items[i].price = (items[i].price)*10 + temp[j];
}
else if(temp[j]=='\n')break;
}
}
printf("\n.........................................\n");
for(i=0;i<n;i++){
printf("%d. %s %d \n",i+1,items[i].name,items[i].price);
}
}
food.txt
8
hot black tea 5
hot lemon tea 6
hot masala tea 7
hot milk tea 9
hot black coffee 7
hot milk coffee 10
finger potato 45
potato chips 35
Here is an minimal example for understanding how to approach this problem statement:
#include<stdio.h>
#define MAX 100
struct node
{
char name[MAX];
int price;
};
int main(void)
{
int inp;
int count_char=0; //COUNTS THE NUMBER OF CHARACTERS OF A NAME
int count_arr=0; //COUNTS THE NUMBER OF SEPARATE NAME-PRICE STRUCTURES USED
struct node EMPTY={{'\0'},0}; //EMPTY STRUCTURE FOR DEFAULT INITIALIZATION
struct node arr[]={[0 ... 99]=EMPTY}; //ARRAY OF STRUCTURES CONTANING 100 ELEMENTS
int temp_count=0;
int count_space=0; //COUNT NUMBER OF SPACES WITHIN THE STRING
while((inp=getchar())!=EOF)
{
if(inp=='\n')
{
count_space=0;
count_arr++;
count_char=0;
continue;
}
if((((inp>='A')&&(inp<='Z'))||((inp>='a')&&(inp<='z')))||(inp==' '))
{
if((count_char==0)&&(inp==' ')) //LEADING SPACE HANDLING
{
continue;
}
if(inp==' ') //SPACE WITHIN STRINGS HANDLING
{
++count_space;
}
else
count_space=0;
if(count_space>1)
continue;
arr[count_arr].name[count_char++]=inp;
}
if((inp>='0')&&(inp<='9'))
{
arr[count_arr].price = (arr[count_arr].price)*10 + inp - '0';
}
}
while(temp_count<count_arr)
{
printf("%s",arr[temp_count].name);
printf("%d\n",arr[temp_count++].price);
}
return 0;
}
If the file contains:
INPUT:
3
xyz 123
abc 89
lmn tub 956
OUTPUT:
xyz 123
abc 89
lmn tub 956
NOTE: There can be tons of things done to streamline this example but this is only a minimal demo.
You can take advantage of the fgets() and sscanf() functions found in stdio.h. This gives the ability to scan the same line of input repeatedly when unexpected input arises, and is generally a better option than using scanf() alone.
In the code below, the line[] array is used to hold the contents of each line of input. This has been made large enough to hold any reasonably sized line, but fgets() ensures that unexpected input will not cause a buffer overflow. More robust code would check for such large inputs anyway, which would cause problems with the remaining input. Note also that the name[] field of the item structure has been enlarged from 25 to 256; there is no reason to be stingy here.
The fgets() function is used to get the first line of input, and if no line is retrieved, or if the first line is non-numeric, an error message is printed to stderr and the program exits with a value of -1.
Then the fgets() function is used again in a loop to read lines of input which are parsed by sscanf(). Here a scanset is used to scan the input line[] and assign to the .name field; it is assumed that the food name contains no numbers. Also note that the .name field will contain any non-numeric characters found before the first digit, so any spaces found before the price will be included in the .name string. These spaces could be trimmed, if desired. Before parsing with sscanf(), the code checks to see if the input line[] is blank, i.e., if the first character is a newline character; if so, the item counter i is decremented, and the loop is continued, skipping any blank lines in the input.
Finally, the contents of the items[] array are displayed for verification.
#include <stdio.h>
struct item {
char name[256];
int price;
};
int main(void)
{
int num_entries; // number of entries, not number of lines
char line[512]; // storage for input lines
if (fgets(line, sizeof line, stdin) == NULL) {
fprintf(stderr, "Empty input file\n");
return -1;
}
if (sscanf(line, "%d", &num_entries) != 1) {
fprintf(stderr, "Formatting error in first line\n");
return -1;
}
struct item items[num_entries];
for (int i = 0; i < num_entries; i++) {
if (fgets(line, sizeof line, stdin) == NULL) {
fprintf(stderr, "Inconsistent file length\n");
return -1;
}
// Do not count blank lines
if (line[0] == '\n') {
--i;
continue;
}
// Assign to struct
if (sscanf(line,
"%255[^0123456789]%d",
items[i].name, &items[i].price) != 2) {
fprintf(stderr, "Formatting error in entry %d\n", i + 1);
return -1;
}
}
// Display contents of array
for (int i = 0; i < num_entries; i++) {
printf("Item %d: %s, $%d\n", i + 1, items[i].name, items[i].price);
}
return 0;
}
Sample interaction:
>$ ./a.out < food.txt
Item 1: hot black tea , $5
Item 2: hot lemon tea , $6
Item 3: hot masala tea , $7
Item 4: hot milk tea , $9
Item 5: hot black coffee , $7
Item 6: hot milk coffee , $10
Item 7: finger potato , $45
Item 8: potato chips , $35
*scnr*:
#include <stddef.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#define STRING(x) #x
#define STRINGIFY(x) STRING(x)
#define MAX_ITEM_NAME_LENGTH 100
typedef struct item_tag {
char *name;
int price;
} item_t;
item_t item_create()
{
item_t new_item = { NULL, 0 };
return new_item;
}
bool item_read(item_t *item)
{
char name[MAX_ITEM_NAME_LENGTH + 1];
int price;
if (scanf(" %" STRINGIFY(MAX_ITEM_NAME_LENGTH) "[^0-9]%d%*[\n]", name, &price) != 2)
return false;
size_t name_length = strlen(name);
if (name_length && isspace((int)name[name_length - 1]))
name[--name_length] = '\0';
item->name = malloc(strlen(name) + 1);
strcpy(item->name, name);
item->price = price;
return true;
}
void item_print(item_t *item, size_t longest_name_length)
{
printf("%-*s %4d\n", (int)longest_name_length, item->name, item->price);
}
void item_destroy(item_t *item)
{
free(item->name);
}
typedef struct products_list_tag {
size_t size;
item_t *items;
size_t longest_name_length;
} products_list_t;
products_list_t products_list_create(void)
{
products_list_t new_products_list = { 0, NULL, 0 };
return new_products_list;
}
bool products_list_read(products_list_t *products_list)
{
size_t num_items;
if (scanf(" %zu%*[\n]", &num_items) != 1)
return false;
else if (!num_items)
return true;
item_t *new_items = calloc(num_items, sizeof *new_items);
size_t num_valid_items = 0;
size_t longest_name_length = 0;
for (size_t i = 0; i < num_items && !feof(stdin); ++i) {
new_items[i] = item_create();
if (!item_read(&new_items[i]))
--i;
else {
++num_valid_items;
size_t name_length = strlen(new_items[i].name);
if (longest_name_length < name_length)
longest_name_length = name_length;
}
}
if (num_valid_items != num_items) {
free(new_items);
return false;
}
new_items = realloc(new_items, num_valid_items * sizeof *new_items);
products_list->items = new_items;
products_list->size = num_valid_items;
products_list->longest_name_length = longest_name_length;
return true;
}
void products_list_print(products_list_t *products_list)
{
for (size_t i = 0; i < products_list->size; ++i)
item_print(&products_list->items[i], products_list->longest_name_length);
}
void products_list_destroy(products_list_t *products_list)
{
for (size_t i = 0; i < products_list->size; ++i)
item_destroy(&products_list->items[i]);
free(products_list->items);
products_list->size = 0;
}
int main(void)
{
products_list_t products = products_list_create();
if (!products_list_read(&products)) {
perror("Failed to read products list!\n\n");
products_list_destroy(&products);
return EXIT_FAILURE;
}
products_list_print(&products);
products_list_destroy(&products);
}
Update:
Just read about a stupid no-other-headers-than-<stdio.h> restriction in a comment on a temporarily deleted, now resored answer.
#include <stdio.h>
#define STRING(x) #x
#define STRINGIFY(x) STRING(x)
#define MAX_ITEM_NAME_LENGTH 100
#define MAX_PRODUCTS_LIST_ITEMS_COUNT 100
/* BEGIN stupid no-other-headers-than-<stdio.h> workaround */
#define MY_EXIT_FAILURE -1
#define true 1
#define false 0
typedef int my_bool;
size_t my_strlen(char const *str)
{
char const *p = str;
while (*p) ++p;
return p - str;
}
char* my_strcpy(char *dst, char *src)
{
char *p = dst;
while (*dst++ = *src++);
return p;
}
/* END stupid no-other-headers-than-<stdio.h> workaround */
typedef struct item_tag {
char name[MAX_ITEM_NAME_LENGTH + 1];
int price;
} item_t;
my_bool item_read(item_t *item)
{
char name[MAX_ITEM_NAME_LENGTH + 1];
int price;
if (scanf(" %" STRINGIFY(MAX_ITEM_NAME_LENGTH) "[^0-9]%d%*[\n]", name, &price) != 2)
return false;
size_t name_length = my_strlen(name);
if (name_length && name[name_length - 1] == ' ')
name[--name_length] = '\0';
my_strcpy(item->name, name);
item->price = price;
return true;
}
void item_print(item_t *item, size_t longest_name_length)
{
printf("%-*s %4d\n", (int)longest_name_length, item->name, item->price);
}
typedef struct products_list_tag {
size_t size;
item_t items[MAX_PRODUCTS_LIST_ITEMS_COUNT];
size_t longest_name_length;
} products_list_t;
products_list_t products_list_init(void)
{
products_list_t new_products_list = { 0 };
return new_products_list;
}
my_bool products_list_read(products_list_t *products_list)
{
size_t num_items;
if (scanf(" %zu%*[\n]", &num_items) != 1)
return false;
else if (!num_items)
return true;
size_t num_valid_items = 0;
size_t longest_name_length = 0;
for (size_t i = 0; i < num_items && !feof(stdin); ++i) {
if (!item_read(&products_list->items[i]))
--i;
else {
++num_valid_items;
size_t name_length = my_strlen(products_list->items[i].name);
if (longest_name_length < name_length)
longest_name_length = name_length;
}
}
if (num_valid_items != num_items)
return false;
products_list->size = num_valid_items;
products_list->longest_name_length = longest_name_length;
return true;
}
void products_list_print(products_list_t *products_list)
{
for (size_t i = 0; i < products_list->size; ++i)
item_print(&products_list->items[i], products_list->longest_name_length);
}
int main(void)
{
products_list_t products = products_list_init();
if (!products_list_read(&products)) {
perror("Failed to read products list!\n\n");
return MY_EXIT_FAILURE;
}
products_list_print(&products, stdout);
}
Output:
hot black tea 5
hot lemon tea 6
hot masala tea 7
hot milk tea 9
hot black coffee 7
hot milk coffee 10
finger potato 45
potato chips 35
I am trying to improve my C skills so I apologize if my question is long. I am having a hard time understanding as to why my struct pointer holds the wrong value in my program, I tried to debug it but I am still relatively new to C and was hoping one of you could tell me what I'm doing wrong here and how I could improve my code and what to focus on.
I am making a program that stores user data on this struct and then prints it out.
typedef struct table {
char *firstName;
char *lastName;
int id;
}USER;
This function below stores the first name
void firstName(int *counter, int *check, USER *pt) {
for (int i = *counter; i < *check; i++) {
pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt));
printf("Enter First Name: ");
getchar();
fgets(pt[i].firstName, MAX_LENGTH, stdin);
}
}
This is just my bool function returning true or false
bool isTrue(char *decision) {
if(*decision == 'Y') {
return true;
}
else {
return false;
}
}
And this is my main
int main(int argc, char **argv) {
USER *pt = calloc(1, sizeof(pt));
int counter = 0, check = 0;
char decision = '\0';
while (1) {
printf("Would you like to enter a user?(Y/N):");
fgets(&decision, 2, stdin);
strtok(&decision, "\n"); //remove the newline char
if (!isTrue(&decision)) {
break;
}
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //the 10 is temporary
}
check = counter + 1; // make sure loop only runs once.
firstName(&counter, &check, pt);
++counter; // increment counter;
}
printStruct(pt, &counter);
return 0;
}
When I run it out sometimes it works fine and returns everything and sometimes it skips a value. This is what I get. It skips the value at pointer index 1 and prints garbage instead.
Would you like to enter a user?(Y/N):N
First name at array 0 is Ermir
First name at array 1 is P#1First name at array 2 is Kevin
First name at array 3 is Blaus
First name at array 4 is Adam
Also I was wondering why is it when I realloc here If i do I get a realloc error when I enter the second name.
if (counter != 0) {
pt = realloc(pt, sizeof(pt) * 10); //realloc(pt, sizeof(pt) * counter + 1) wont work
}
char decision = '\0';
...
fgets(&decision, 2, stdin);
You are only allocating 1 char but are at least reading 2 chars into it. Fix by allocating a sufficiently sized array for decision.
Unrelated but in firstName() pt[i].firstName = calloc (MAX_LENGTH, sizeof(pt)); should be pt[i].firstName = calloc (MAX_LENGTH, 1);
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm trying to access a pointer inside of a struct, I tried placing * in front of the struct pointer
to access the pointer inside the struct, but it segfaults.
code segfaults on *ptr->numberOfClients = clients;
int getNumberOfClients(struct fuzzerObj *ptr)
{
int rtrn;
long clients;
char *input;
char *holder = NULL;
printf(BOLDBLUE"How many clients will you be connecting to this fuzz server?\n"RESET);
printf(BOLDBLUE"---> "RESET);
rtrn = getUserInput(&input);
if(rtrn < 0)
{
errorHandler("Can't Get User input\n", FUNCTION_ID_GET_NUMBER_OF_CLIENTS);
return -1;
}
if (strlen(input))
{
clients = strtol(input, &holder, 10);
if (input == holder)
{
errorHandler("invalid long conversion\n", FUNCTION_ID_GET_NUMBER_OF_CLIENTS);
return -1;
}
}
else
{
errorHandler("No Value To Compute\n", FUNCTION_ID_GET_NUMBER_OF_CLIENTS);
return -1;
}
*ptr->numberOfClients = clients;
free(input);
return 0;
}
int getUserInput(char **buf)
{
int i = 0, max = 1024, c;
*buf = reallocarray(NULL, 1025, sizeof(char *));
if(*buf == NULL)
{
errorHandler("Mem Error\n", FUNCTION_ID_GET_USER_INPUT);
free(*buf);
return -1;
}
while (true) { // skip leading whitespace
c = getchar();
if (c == EOF) break; // end of file
if (!isspace(c)) {
ungetc(c, stdin);
break;
}
}
while (true) {
c = getchar();
if (isspace(c) || c == EOF) // at end, add terminating zero
buf[i] = 0;
break;
}
*buf[i] = c;
if (i==max-1) { // buffer full
max = max+max;
*buf = (char*)realloc(*buf,max); // get a new and larger buffer
if (buf == 0)
{
errorHandler("Realloc Error\n", FUNCTION_ID_GET_USER_INPUT);
return -1;
}
}
i++;
return 0;
}
and here's the struct
struct fuzzerObj
{
int parserResponse;
int *numberOfClients;
int *clientFuzzerType[1024];
int *clientSockets[1024];
int *clientApplication[1024];
int *clientFuzzer[1024];
int *connectedClients;
int *socket;
int *fuzzer;
int *application;
dispatch_queue_t queue;
};
There is a major problem that I see (unless you've not shown it in your code snippets). numberOfClients is declared as such:
struct fuzzerObj
{
...
int *numberOfClients;
...
};
Before you assign an int to it. You must assign memory to store the int:
1.
ptr->numberOfClients = malloc(sizeof(*(ptr->numberOfClients)));
*(ptr->numberOfClients) = clients;
...
free(ptr->numberOfClients);
2.
int temp;
ptr->numberOfClients = &temp;
*(ptr->numberOfClients) = clients;
...
// Write to a file here???
Another question... why are the fields of fuzzerObj pointers? If you make them ints instead of pointers to ints, you wouldn't have the difficulties you're experiencing.
EDIT
The second method shown above is not safe because once the function that has declared temp returns, temp no longer exists, and therefore numberOfClients doesn't have valid memory, and should not be used.
It is totally unclear why data member numberOfClients defined as a pointer instead of to be an object of type int
int *numberOfClients;
Try the following
ptr->numberOfClients = ( int * )malloc( sizeof( int ) );
if ( ptr->numberOfClients ) *ptr->numberOfClients = clients;
Also take into account that variable clients is defined as
long clients;
In some implementations sizeof( lomg ) can be greater than sizeof( int ).
It is in general a bad design. It is unclear whether data members of the structures were initialized and corresponding memory were allocated.
I'm still new in C. I'm doing an enviroment variable task and I'm having a problem in processing my string. I would like to pass a variable that represent the environment variable, and replace a value that has ${...} with environment value if that string are same as the enviroment key. Here are the codes:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void replace_env(char *string, char *env)
{
int y = 0;
int x = 0;
int j = 0;
int i = 0;
int n = 0;
int val_length;
int location2[100];
char *tmp3[BUFSIZ];
char env_key[BUFSIZ];
char env_val[BUFSIZ];
char env_var[sizeof(env)][BUFSIZ];
char user_input[BUFSIZ];
char final_string[BUFSIZ];
char tmp_key[100][BUFSIZ];
tmp3[x]=env;
strncpy(env_var[x],tmp3[x],sizeof(tmp3));
for(x=0;env_var[y][x] != '=';x++) //this is to get the environment key
{
env_key[x] = env_var[y][x];
}
x++;
for(j=0;env_var[y][j] != '\0';j++) //this is to get the environment value
{
env_val[j]=env_var[y][x];
x++;
}
val_length = strlen(env_val);
j=0;
y=0;
strncpy(user_input,string,sizeof(user_input));
for(x = 0;user_input[x] !='\0';x++)
{
if (user_input[x] =='$')
{
x++;
if(user_input[x] == '{')
{
x++;
y=0;
while(user_input[x]!='}')
{
tmp_key[i][y] = user_input[x];
x++;
y++;
}
i++;
}
}
}
tmp_key[i][y]='\0';
i=0;
for(x = 0;user_input[x] !='\0';x++) //I think my problem is starting from here.
{
if (user_input[x] !='$')
{
final_string[j]=user_input[x];
j++;
}
else
{
x++;
if((user_input[x]== '{')&&(strncmp(tmp_key[i],env_key,sizeof(tmp_key))==0))
{
while(user_input[x]!='}')
{
x++;
}
strcat(final_string,env_val);
j=j+val_length;
}
else
{
final_string[j]=user_input[x];
j++;
}
}
}
printf("output result = %s \n",final_string);
}
int main() {
char s[100];
sprintf(s, "jack${ABC}zack${DEF}");
replace_env(s, "ABC=/home/fikrie/Documents");
replace_env(s, "DEF=/tmp");
if (strcmp(s, "jack/home/fikrie/Documentszack/tmp")==0) {
printf("pass\n");
} else {
printf("fail\n");
}
printf("--------------------------------------------------------\n");
return 0;
}
To make it more clearer, here are the result:
env_var = ABC=/home/fikrie/Documents
env_key = ABC
env_val = /home/fikrie/Documents
input = jack${ABC}zack${DEF}
after strcat result is = jack/home/fikrie/Documents
j value is 26
after strcat result is = jack/home/fikrie/Documentszack/home/fikrie/Documents
j value is 52
output result = jack/home/fikrie/Documentszack/home/fikrie/Documents
env_var = DEF=/tmp
env_key = DEF
env_val = /tmp
input = jack${ABC}zack${DEF}
output result = jack{ABC}zack{DEF}ocumentszack/home/fikrie/Documents
fail
--------------------------------------------------------
As you can see, ABC are sent into the replace_env function. And it does replace the ${ABC} properly, followed with a string zack.Then the problem occures where ${DEF} are replaced with ABC key and not maintained as ${DEF}
When the DEF are sent during the second call of replace_env function, things got more wierd. Both ABC and DEF are not recognized. Even worse, the character at the back are still there.
My expectation is:
For the first call of replace_env:
jack/home/Fikrie/Documentszack${DEF}
For the second call of replace_env:
jack/home/Fikrie/Documentszacl/tmp
after the strcmp passed, the final_string will be cleared again.
All help are really appreciated. I dont expect an answer. I prefer a knowledge or guidance rather than just solving it blankly. Just need a clear explanation on my fault because I have been editing this code for almost a month and everything looks so blurry now. I know there are ways to solve it using memory functions, allocation etc. But this task is about string manipulation. I am running this on Ubuntu OS. Sorry for my bad english.
I know you didn't ask for this, but consider this. Learning the C string functions is worth your time.
#include <stdio.h>
#include <string.h>
void sub(char *s, char *env, char *value) {
char buf[BUFSIZ], *src = s, *dst = buf;
int n = strlen(env);
while(*src) {
if(strncmp(src, env, n) == 0) {
dst += strlen(strcpy(dst, value));
src += strlen(env);
} else {
*dst++ = *src++;
}
}
*dst = 0;
strcpy(s, buf);
}
void replace_env(char *s, char *env) {
char copy[BUFSIZ], tmp[BUFSIZ];
strcpy(copy, env);
char *eq = strchr(copy, '=');
if(eq == 0) {
printf("No '=' found in '%s'\n", env);
return;
}
*eq = 0;
sprintf(tmp, "${%s}", copy);
sub(s, tmp, eq+1);
}
int main() {
char s[100];
sprintf(s, "jack${ABC}zack${DEF}");
replace_env(s, "ABC=/home/fikrie/Documents");
replace_env(s, "DEF=/tmp");
if (strcmp(s, "jack/home/fikrie/Documentszack/tmp")==0) {
printf("pass\n");
} else {
printf("fail\n");
}
printf("--------------------------------------------------------\n");
return 0;
}
I'm trying to figure out how to search a list of names that are inputted into a string array. If the name entered is part of the original array, then the search function should return the position of the string in the array; if the string is not found, it should return -1. If -1 is returned then I want to be able to print out "not found", which doesn't seem like it would be too hard to figure out, but if the name is found, I want to be able to print out the position at which the name is found.
Here is my code, obviously I'm new to this, so I might have butchered how this is supposed to be done. The rest of my code seems to work fine, but it's this function that has me at a loss.
#include<stdio.h>
#include<conio.h>
#include<string.h>
#define MAX_NAMELENGTH 10
#define MAX_NAMES 5
void initialize(char names[MAX_NAMES][MAX_NAMELENGTH]);
int search(char names[MAX_NAMES][MAX_NAMELENGTH],int i,Number_entrys);
int main()
{
char names[MAX_NAMES][MAX_NAMELENGTH];
int i;
initialize(names);
search(names,i,Number_entrys);
search_result= search(names,i,Number_entrys);
if (search_result==-1){
printf("Found no names.\n");
}
if(search_result==0){
printf("Name found");
} getch();
return 0;
}
void initialize(char names[MAX_NAMES][MAX_NAMELENGTH])
{
int i, Number_entrys;
printf("How many names would you like to enter to the list?\n");
scanf("%d",&Number_entrys);
if(Number_entrys>MAX_NAMES){
printf("Please choose a smaller entry\n");
}else{
for (i=0; i<Number_entrys;i++){
scanf("%s",names[i]);
}
}
for(i=0;i<Number_entrys;i++){
printf("%s\n",names[i]);
}
}
int search(char names[MAX_NAMES][MAX_NAMELENGTH],int i)
{
int j, idx;
char name[MAX_NAMELENGTH];
printf("Now enter a name in which you would like to search the list for:");
scanf("%s", name);
for(x = 0; x < Number_entrys; x++) {
if ( strcmp( new_name, names[x] ) == 0 ){
/* match, x is the index */
return x;
}else{
return -1;
}
}
}
There are several problems here.
The purpose of search is to ask the user to enter a single name to be searched for. So why is
char new_name[MAX_NAMES][MAX_NAMELENGTH];
You need only a single array
char new_name[MAX_NAMELENGTH];
Then you have a loop you just go round once, so you don't need a loop
scanf("%s",new_name);
would be enough. This feels like you have copied the code you used to fill your array of names, but haven't really understood its essence.
Another problem is that you have no control on how long a name the user might enter. What would happen if the user typed a very long name? You'd over-fill the array and your program will probably crash and burn. Read this article to learn about how to control this.
To be really pedantic you should also check the return code from scanf, you are expecting to read one item so the return value should be 1, anything else would be an error.
Then you are trying to use strstr(), to look through an array of char arrays. The strstr documentation says that its purpose is to search for a substring within a string rather than search through an array of strings.
So instead just search the array by hand
/* what is i? the number of items used in the array? */
for(x = 0; x < i; x++) {
if ( strcmp( new_name, names[x] ) == 0 ){
/* match, x is the index */
return x;
}
}
/* here with no match */
return -1;
In your main
int search_result;
search_result = search( /* etc */ );
if ( search_result == -1 ) {
/* print "not found" here */
} else {
/* print something else */
}
You means like this:
int search(char names[MAX_NAMES][MAX_NAMELENGTH], int i)
{
int j, idx;
char name[MAX_NAMELENGTH];
printf("Now enter a name in which you would like to search the list for:");
scanf("%s", name);
idx = -1;
for(j = 0; j < i; j++){
if(strstr(names[i], name) != NULL){
idx = j;break;
}
}
return idx;
}
(8) ...
Maybe we'll turn it all around
'Cause it's not too late
It's never too late!! (8)
:) !
Sorry about the song ^_^... oh Well, I was having fun with this question for a couples of minutes, I hope this code help you out a little more, with regards:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* return array of indexs */
int*
search(const char *list, size_t slen, const char **arr_names, size_t arrlen)
{
int *arr_idx;
int j,i,idx;
i=idx=0;
arr_idx = malloc(sizeof(int)*arrlen+1);
if(!arr_idx)
exit(EXIT_FAILURE);
for(i=0; i<slen; i++) {
for(j=0; j<arrlen ; j++) {
if(!strncmp(&list[i], &arr_names[j][0], strlen(arr_names[j]))) {
arr_idx[idx] = j;
idx++;
}
}
}
arr_idx[idx] = -1; /* -1 terminated array */
if(!idx) {
free(arr_idx);
return NULL; /* found no names */
}
return arr_idx;
}
/* I'm a sick [something], nul terminated strings :P */
const char *string = "My favorite artists: ATB, Nujabes and Bonobo also Aphex Twins is nice, along with Trapt and Breaking Benjamin.\0";
const char *names[] = {"ATB\0", "Scifer\0", "Aphex\0", "Bonobo\0", "Nujabes\0", "Tipper\0"};
#define N_NAMES 6
int
main(void)
{
int i;
int *array;
array = search(string, strlen(&string[0]), names, N_NAMES);
if(!array) {
puts("Found no names.\n");
return EXIT_SUCCESS;
}
printf("Names found: ");
for(i=0; array[i]!=-1; i++)
printf("%s,", names[array[i]]);
printf("\b \n");
free(array); /* important */
/* system("pause"); */ /* NOTE: decomment this if you're on windows */
return EXIT_SUCCESS;
}
ran some tests:
~$ ./program
output
Names found: ATB,Nujabes,Bonobo,Aphex