Creation of Dynamic Array of Strings in C - arrays

So I am pretty much trying to create an array that functions as following:
1)I enter a string (in a temporary array like char temp[...] for example)
2)I create a while loop that ends when the first character of temp is \x0
3)Inside the loop I use the malloc function to create space for each string
4)I print the strings
Problem is that whenever i try to run my program it crushes and the compiler isn't helping me much.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE 80
int main(){
char **pin;
char temp[LINE];
int index = 0;
puts("Gimme Books' Titles:");
gets(temp);
while(temp[0] != '\x0'){
pin[index] = (char*)malloc(strlen(temp)+1);
strcpy(pin[index], temp);
index++;
gets(temp);
}
puts("\nBooks' List:");
for(int k = 0; k < index; k++){
puts(pin[k]);
}
}
Anyone here who can help me find out what I am doing wrong?

The link in the comments above [mostly] assumes that we know the number of elements before we allocate the array.
Thus, it's not as useful when we can only get the number of elements by reading the input file. For TTY input from stdin this won't work too well because we can't rewind the file.
A dynamic array is generally useful. So, I've created one that allows arbitrarily sized array elements. And, it can grow/expand as we add new elements.
And, for demo purposes here, I've created a "book" structure that stores Author's name and book title.
Here is the code. It is annotated:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
// general dynamic array control
typedef struct {
void *arr_base; // pointer to data
size_t arr_size; // bytes / element
size_t arr_count; // number of elements in use
size_t arr_capacity; // number of elements allocated
} arr_t;
// book control
typedef struct {
char *book_last; // author's last name
char *book_first; // author's first name
char *book_title; // book title
} book_t;
// arrnew -- allocate new array
arr_t *
arrnew(size_t siz)
{
arr_t *arr = calloc(1,sizeof(*arr));
// store the number of bytes in each element
arr->arr_size = siz;
return arr;
}
// arrappend -- get new element in array
// RETURNS: pointer to element
void *
arrappend(arr_t *arr)
{
size_t index;
void *ptr;
// get index of element to store into and increase the in use count
index = arr->arr_count++;
do {
// we have enough space for the new element already
if (arr->arr_count < arr->arr_capacity)
break;
// increase allocated amount
// NOTE: the increment is arbitrary
arr->arr_capacity += 10;
// grow the array
arr->arr_base = realloc(arr->arr_base,
arr->arr_capacity * arr->arr_size);
// got the larger array
if (arr->arr_base != NULL)
break;
perror("arrappend");
exit(1);
} while (0);
// point to element we can store into
ptr = arr->arr_base;
ptr += index * arr->arr_size;
return ptr;
}
// arrtrim -- trim array to number of elements actually used
void
arrtrim(arr_t *arr)
{
arr->arr_capacity = arr->arr_count;
arr->arr_base = realloc(arr->arr_base,arr->arr_capacity * arr->arr_size);
if (arr->arr_base == NULL) {
perror("arrtrim");
exit(1);
}
}
// arrfree -- free up array storage
void
arrfree(arr_t *arr)
{
free(arr->arr_base);
free(arr);
}
int
main(void)
{
char buf[300];
char *cp;
book_t *book;
// echo line if input is _not_ a tty [mostly for demo]
struct termios tio;
int echo = tcgetattr(fileno(stdin),&tio) < 0;
// get new array
arr_t *arr = arrnew(sizeof(book_t));
printf("Gimme Books's Titles:\n");
while (1) {
// get next line -- stop on EOF
char *cp = fgets(buf,sizeof(buf),stdin);
if (cp == NULL)
break;
// echo line if input is _not_ a tty
if (echo)
fputs(buf,stdout);
// strip newline
buf[strcspn(buf,"\n")] = 0;
// stop on blank line
if (buf[0] == 0)
break;
// get new book struct
book = arrappend(arr);
// get author's last name
char *tok = strtok(buf," \t");
book->book_last = strdup(tok);
// get author's first name
tok = strtok(NULL," \t");
book->book_first = strdup(tok);
// get the book title
tok += strlen(tok);
++tok;
for (; *tok != 0; ++tok) {
if (*tok != ' ')
break;
}
book->book_title = strdup(tok);
}
arrtrim(arr);
// show all the books
book = arr->arr_base;
for (size_t idx = 0; idx < arr->arr_count; ++idx, ++book)
printf("Last: %s First: %s Title: %s\n",
book->book_last,book->book_first,book->book_title);
// release storage for each book
book = arr->arr_base;
for (size_t idx = 0; idx < arr->arr_count; ++idx, ++book) {
free(book->book_last);
free(book->book_first);
free(book->book_title);
}
// release array storage
arrfree(arr);
return 0;
}
Here is the program input:
Lambstewer Abel A Tale of Two Cities
Smith John A baker's tale
Jones Fred Never On Sunday
Here is the program output:
Gimme Books's Titles:
Lambstewer Abel A Tale of Two Cities
Smith John A baker's tale
Jones Fred Never On Sunday
Last: Lambstewer First: Abel Title: A Tale of Two Cities
Last: Smith First: John Title: A baker's tale
Last: Jones First: Fred Title: Never On Sunday

Related

c - Access violation reading location exception when use scanf to read string from user

I'm trying to get to read string input from user and store it in two dim array using pointers.
I'm getting Access violation reading location exception when trying to use those strings.
first I declared char*** that will store pointers for two dim array , then I use for loop to initial two dim array for each cell.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define WORDLEN 80
#define DEFLEN 200
#define KEYVALUE 2
char*** MallocDic(int dictionarySize);
char** MallocDicElement(char* word, char* definition);
void PrintDictionary(char*** dictionary, int dictionarySize);
int main()
{
int dictionarySize;
printf("Please enter dictionary size\n");
scanf("%d", &dictionarySize);
char*** dictionary = MallocDic(dictionarySize);
int i;
for (i = 0; i < dictionarySize; i++) {
char* inputWord = (char*)malloc(WORDLEN * sizeof(char));
char* inputDef = (char*)malloc(DEFLEN * sizeof(char));
if (inputWord == NULL || inputDef == NULL)
{
printf("Failed to allocate memory!\n");
exit(1);
}
printf("enter word : \n");
scanf("%s", inputWord);
printf("enter definition : \n");
scanf("%s", inputDef);
printf("word : %s ,def : %s\n", inputWord, inputDef);
//dictionary[i] = MallocDicElement(inputWord, inputDef);
//free(inputDef);
free(inputWord);
}
printf("Print Dictionary : \n");
//PrintDictionary(dictionary, dictionarySize);
}
char*** MallocDic(int dictionarySize) {
char*** p;
p = (char***)malloc(dictionarySize * sizeof(char**));
return p;
}
char** MallocDicElement(char* word, char* definition) {
char** p = (char**)malloc(KEYVALUE * sizeof(char*));
int i;
for (i = 0; i < KEYVALUE; i++) {
if (i == 0) {
p[i] = (char*)malloc(WORDLEN * sizeof(char));
p[i] = word;
}
else {
p[i] = (char*)malloc(DEFLEN * sizeof(char));
p[i] = definition;
}
}
return p;
}
void PrintDictionary(char*** dictionary, int dictionarySize) {
int i = 0, j = 0;
for (i = 0; i < dictionarySize; i++) {
for (j = 0; j < KEYVALUE; j++) {
printf("word : %s\n", dictionary[i][0]);
printf("definition : %s\n", dictionary[i][1]);
}
}
}
The logic breaks in when trying to print the first string.
what am I missing here ?
Thanks for any help.
At least these problems.
Leaked memory
Code allocates memory and saves the pointer to that allocation to p[i] and then copies the pointer word to p[i] in the next line. This loses the pointer returned from malloc().
p[i] = (char*)malloc(WORDLEN * sizeof(char));
p[i] = word; // ???
Much more likely OP wants to copy the string, pointed to by word to the memory pointed to by p[i].
p[i] = malloc(WORDLEN);
strcpy(p[i], word);
More common to allocate only what is needed.
p[i] = malloc(strlen(word) + 1);
strcpy(p[i], word);
Research strdup().
Error checking omitted for brevity.
Do not use "%s", "%[]" without a width in *scanf()
Limit acceptable input to 1 less than the size of the destination array.
"%s" does not read and save spaces
The below will not work to read a definition that contains spaces.
printf("enter definition : \n");
scanf("%s", inputDef); // Stops after first word
Scanning will stop at the first white-space after reading some non-white-space.
Perhaps:
scanf(" %199[^\n]", inputDef);
Check return value of input functions
if (scanf(" %199[^\n]", inputDef) != 1) {
Handle_input_error();
}
Other:
Avoid hard to read & maintain allocation
Rather than cast (not needed) and size to the type (defined someplace else), allocate to the size of the referenced object - no type needed to get wrong.
// p = (char***)malloc(dictionarySize * sizeof(char**));
p = malloc(sizeof p[0] * dictionarySize);
Easier to code right, review and maintain.
At the risk of a non-answer here (not working with your extant code) I would like to suggest you take the time to better structure your data. Even something as simple as:
// A `dictionary` is an array of `capacity` entries, `size` of which are in use.
// Elements are kept in lexicographical order.
struct dictionary
{
struct entry
{
const char * word;
const char * definition;
};
struct entry * entries;
size_t size;
size_t capacity;
};
typedef struct dictionary dictionary;
This makes life about a bazillion times easier when dealing with stuff. You can now create a couple of useful functions:
dictionary * new_dictionary( size_t capacity );
void free_dictionary( dictionary * dict );
This structured nature makes it easier to manage individual parts. In particular, your users can pass the pointer to the dictionary around and never have to worry about it changing. For example, suppose you want to update the dictionary’s capacity:
void set_dicitionary_capacity( dictionary * dict, size_t new_capacity )
{
if (new_capacity < dict->size) return;
struct entry * new_entries = realloc( dict->entries, new_capacity * sizeof dict->entries[0] );
if (!new_entries) return;
dict->capacity = new_capacity;
dict->entries = new_entries;
}
This idea of having functions to interface with your opaque dictionary object is the basis for basic data encapsulation. Doing so makes the using code so much easier:
dictionary * words = new_dictionary( 1000 );
if (!words) fooey();
update_dictionary( words, "hello", "a greeting" );
update_dictionary( words, "world", "the Earth; a planet; any organism’s collective society" );
printf( "There are %zu words in the dictionary.\n", dictionary_size( words ) );
const char * desc = find_word( words, "there" );
printf( "Obi Wan can%s use this dictionary.\n", desc ? "" : "not" );
free_dictionary( words );
Hopefully we can already see how things are easier to grok on every level.
In other words, write code in such a way as to make meaning and structure as clear as possible. This helps to reduce the amount of failure our befuddled minds can generate when writing code.

find words that match user input with strstr

In my register, I want to find all the words that match user input and display them.
For example if I have words like redapple, rottenapple, apple, banana in my register.
And user inputs apple I want to be able to dispaly redapple, rottenapple, apple and their itemnumber and inventory balance. I cannot display in the right way and cannot figure it why, have tried different way and I will post my last try. Thank you!
void search(Car a[],int nr){
char ItmName[50];
int i;
while(1){
printf("Type item name (q for menu): ");
scanf("%s%*c", &ItmName);
if(strcmp(ItmName,"q")==0){
return;
}else{
for(i=0;i<nr;i++){
char *word = strstr(a[i].name,ItmName);
for(i=0;i<nr;i++)
if(word==itemN){
printf("%d\t\t%s\t\t%d\n", a[i].itemNmr, a[i].name, a[i].inventory);
}
return;
}
}
}
}
Your nested loop use the same control variable, i, and continuation condition, which ensures only one iteration of the outer loop occurs.
The contents of the loop make little sense. You repeatedly compare a pointer to the first element of the input buffer (itemN; pressumably itemName) against the pointer value returned by strstr, after it looks through the name field of only the first element of the a array for the substring provided in itemName.
Rewritten verbosely, this reads as
for (i = 0; i < nr; i++) {
for (i = 0; i < nr; i++) {
if (strstr(a[0].name, itemName) == &itemName[0]) {
printf(/* some information */);
}
}
}
which hopefully you can see makes no sense. A pointer value that points to an element of a[0].name will never be equal to the pointer value that points to the first element of itemName - as that would require their memory to overlap somehow.
In any case, this should not require any nested loops, as this can be done with a linear search of your array of structures.
First suggestion: move the user input to outside the function. Make search accept a third argument, a string to search for in each structures name. Separately (and repeatedly) take user input and then call this function.
Second suggestion: forget scanf exists entirely. Use fgets (and sscanf if you need to extract formatted data from the string).
Here's a cursory example of a linear search function:
#include <stdio.h>
#include <string.h>
typedef struct {
char name[128];
unsigned inventory;
} Car;
void search(Car *cars, size_t length, const char *query)
{
for (size_t i = 0; i < length; i++)
if (strstr(cars[i].name, query))
printf("NAME: [%s]\tQUANT: [%u]\n", cars[i].name, cars[i].inventory);
}
int main(void)
{
Car cars[] = {
{ "redapple", 10 },
{ "rottenapple", 7 },
{ "foo", 4 },
{ "bar", 15 },
{ "candyapple", 11 }
};
size_t len = sizeof cars / sizeof *cars;
while (1) {
char buf[512];
printf("Enter a search string (. = exit): ");
fflush(stdout);
if (!fgets(buf, sizeof buf, stdin))
return 1;
if ('.' == *buf)
return 0;
/* remove any trailing CRLF */
buf[strcspn(buf, "\r\n")] = '\0';
search(cars, len, buf);
}
}

In C, how do I remove identical, and consecutive lines in a char array?

I'm looking for some help in creating a function.
The funciton, deleteIdents(), will remove identical lines in a char array, given they are consecutive. It will keep one of the identical lines.
I don't need to check if the whole line is identical. Just the first 79 chars, MAXCHARS, will be fine for this scenario.
So, for example, if my array contains
Hello World
Hi World
Hello World
Hello World
Hello World
Hi there
it will be changed to
Hello World
Hi World
Hello World
Hi there
In my head, the function would look similar to:
int deleteIdents(char *a)
{
int i;
for (i=0; i<=MAXCHARS; i++) {
if (a[i] != '\n')
/* copy into new array */
}
}
}
but I'm unsure. If you have a solution, I'd be glad and thankful to hear it :)
Well read first line than second, compare them if they are equal go into the loop until they are not equal. So here is code:
char *first_line = malloc(MAXLINE);
char *second_line = malloc(MAXLINE);
getline(first_line);
do {
getline(second_line);
} while (strcmp (first_line, second_line));
For getline() implementation search SO there are plenty of examples. Or here you have mine.
Another example how it can be achived. Idea is to keep 2 pointers, and increment first one only if entries are different. Also some additional storage is allocated to avoid memory leaks for entries that has been overriden.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int unique(char **strings, int size) {
if (!strings) {
return -1;
}
int head = 0, newHead = 0, duplicatedElementsHead = 0;
//Save duplicates to avoid memory leaks
char** duplicatedEntries = malloc(size*sizeof(char*));
while (head < size) {
//String are the same
if (!strcmp(strings[head], strings[newHead])) {
if (head != newHead) {
duplicatedEntries[duplicatedElementsHead++] = strings[newHead];
}
++head;
} else {
strings[++newHead] = strings[head++];
}
}
//Put duplicated entries after new end
int idx = 0, tmpHead = newHead + 1;
for (; idx < duplicatedElementsHead; ++idx) {
strings[tmpHead++] = duplicatedEntries[idx];
}
free(duplicatedEntries);
return newHead;
}
int main() {
char **strings = malloc(8*sizeof(char*));
strings[0] = "Hello World";
strings[1] = "Hi World";
strings[2] = "Hi World";
strings[3] = "Hello World";
strings[4] = "Hello World";
strings[5] = "Hi there";
strings[6] = "Hia";
strings[7] = "Hi";
int newEnd = unique(strings, 8);
for (int i=0; i < newEnd; ++i) {
printf("%s\n", strings[i]);
}
free(strings);
}
You are essentially writing the core functionality of the unix/linux utility, 'uniq'.
cat filename | sort | uniq > newfile
#or skip sort, since you didn't mention
cat filename | uniq > newfile
You could just use popen and uniq (something like this...)
FILE *uniqfh;
uniqfh = popen("cat file1 | uniq" , "r");
if (uniqfh == NULL) { //handle error
}
while( fgets(uniqfh, buffer, buffersize) ) printf("%s\n",buffer);
But seriously, you could write the core of uniq(),
static long MAXUNIQ=79; //or whatever you want
char*
isdup(char* prev, char* next, long len)
{
//if( !prev || !next) error
long n = len<=0 ? MAXUNIQ : len;
for( ; *prev==*next && n --> 0; ) { //down-to operator (sic)
; //clearly nothing happening here!
}
return( (n<1) || !(*p+*n) );
}
/yeah, this is actually strncmp, but hey
You need an array of 'strings' (char* or char[]), let's read them,
char* ray[ARRAYMAX]; //define how many elements of your arRay
//could use, char** ray; and malloc(ARRAYMAX*sizeof(char*))
long
read_array(FILE* fh, char* ray[])
{
char buffer[MAXLINE+1];
long count=0;
while( fgets(buffer,sizeof(buffer),fh) ) {
//you could eat dups here, or in separate function below
//if( (count<1) && !isdup(ray[count-1],buffer,MAXUNIQ) )
ray[count++] = strdup(buffer);
}
//ray[0] through ray[count-1] contain char*
//count contains number of strings read
return count;
}
long
deleteIdents(long raysize, char* ray[]) //de-duplicate
{
long kept, ndx;
for( ndx=1, kept=0; ndx<raysize; ++ndx ) {
if( !isdup(ray[kept],ray[ndx]) ) {
ray[kept++] = ray[ndx];
}
else {
free(ray[ndx]);
ray[ndx] = NULL; //not entirely necessary,
}
}
return kept; //new ray size
}
And you will need to to this to call it...
...
long raysize;
char* ray[ARRAYMAX] = {0}; //init to null pointers
raysize = read_array(fopen(filename,"r"),ray);
raysize = deleteIndents(raysize,ray);
...
Later, you will need to free the malloc'ed strings,
for( ; 0 <-- raysize; ) { free(ray[raysize]); ray[raysize] = NULL; }
The following program does what you need on an array of string elements. We navigate the array with two pointers, initialised to the first and second elements. We run a loop of array_n - 1 comparisons of one element to the next one, comparing both strings... if they are different, we copy the *source_ptr string pointer to the *target_ptr place. If they are different we only increment the source_ptr, so it points to the next array string, but without copying it (this makes us to effectively delete the pointer) We are also managing the new array (we have used the same array as source and destination, as we can only delete array elements, so each time we have a greater hole between both pointers)
pru.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* array of strings */
char *array[] = {
"Hello World",
"Hi World",
"Hello World",
"Hello World",
"Hello World",
"Hi there",
};
size_t array_n = sizeof array / sizeof *array;
int main()
{
int i;
char **target_ptr = array, **source_ptr = array + 1;
size_t new_length = 1;
for (i = 1; i < array_n; i++) {
/* if strings pointed to by pointers are equal */
if (strcmp(*target_ptr, *source_ptr) == 0) {
/* go to the next, effectively discarding the second pointer */
source_ptr++;
} else {
/* copy both pointers in place, to the destination array */
*target_ptr++ = *source_ptr++;
new_length++; /* increment array length */
}
}
/* finally, we have in the array only the good pointers */
/* print'em */
for (i = 0; i < new_length; i++)
printf("%s\n", array[i]);
exit(0);
}
and that's all.
sample run:
$ pru
Hi World
Hello World
Hi there
Hello World
$ _

c - dynamically allocate variable names

I am trying to take number of inputs from a user and take the inputs then and store them under dynamically created variable names. can anyone help?
I want to take the number of array user want to input then create the exact number of variables which maintains a common pattern so I can know which array is under which variable and I can call them for further processing.
My current code is as follows
int input, eqn, m, i,n,x;
char inputarr[100], eqnarr[100];
printf("Enter number of variables: ");
scanf("%d",&n);
m=n;
printf("Enter your variables: \n");
while(n!=-1){
gets(inputarr[n]);
n--;
}
while(m!=0){
puts(inputarr[m]);
printf("\n");
m--;
}
my inputs are like
2 (here 2 is number of inputs user intended to give)
a = 3
b = 4
I need to save them in 2 variables say var1 and var2 as I need to work with them later.
C does not support dynamically created variables. You can instantiate dynamic objects through calls to malloc(), but these will not be named. In C, names are just labels used to associate names to memory locations at compile time, and resolved at link time. It is way too late at run time.
You can create a mapping from names to int values, but you cannot create new variables. A Mapping will work for you. You need to create a method to add a named value to your mapping, a method to retrieve the value, a method to update its value, and for completeness, you need a fourth method to delete an element when you no longer need it.
Here is a simple example of mapping variable names to int values using a dynamic lookup table. To be complete, you would need to add methods for updating values, and deleting them, etc.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#define MAX_VARIABLES 100
typedef struct Lookup_Entry_Struct {
char* Name;
int Value;
} LookUp_Entry;
typedef struct Mapping_Struct {
int MaxEntries;
int NumEntries;
LookUp_Entry* mapping;
} Mapping;
void initMapping(Mapping* map, int MaxEntries)
{
map->NumEntries = 0;
map->MaxEntries = MaxEntries;
map->mapping = calloc(sizeof(LookUp_Entry), MaxEntries);
if (map->mapping == NULL) {
// Failed to allocate the Mapping table
fprintf(stderr, "Failed to alloc Mapping table of %d entries\n", MaxEntries);
map->MaxEntries = 0;
}
}
bool addMap(Mapping* map, char* Name, int Val)
{
bool Added = false;
if (map->NumEntries < map->MaxEntries) {
// There is still room in the table, add this new variable
LookUp_Entry* newEntry = &(map->mapping[map->NumEntries]);
newEntry->Value = Val;
newEntry->Name = malloc(strlen(Name)+1);
strcpy(newEntry->Name, Name);
map->NumEntries++;
Added = true;
}
return Added;
}
int lookup(Mapping* map, char* Name)
{
int val = -1;
int i = 0;
bool Found = false;
// Search the map to see if we can find Name
for(i=0; i < map->NumEntries && !Found; i++)
{
LookUp_Entry* entry = &(map->mapping[i]);
if (strcmp(entry->Name, Name) == 0) {
// Found a match, return the value in *Val
val = entry->Value;
Found = true;
}
}
if (!Found)
fprintf(stderr, "lookup of \"%s\" not found in map\n", Name);
// Found value, or -1 if not found
return val;
}
void getVariablesFromUser(Mapping* map)
{
#define MAXNAMELEN 100
// Code modified from Buno's sample
int NumVariables = 0;
int i;
char inputName[100];
int inputVal;
while ((NumVariables<1) || (NumVariables > MAX_VARIABLES)) {
printf("Enter number of variables: ");
scanf("%d", &NumVariables);
if (NumVariables<0 || NumVariables>MAX_VARIABLES)
fprintf(stderr, "Please enter no more than %d variables!\n", MAX_VARIABLES);
}
printf("Init mapping for %d variables\n", NumVariables);
initMapping(map, NumVariables);
for(i=0; i<NumVariables; i++) {
printf("Enter variable #%d name and initial value: ", i+1);
scanf("%s %d", &(inputName[0]), &inputVal);
printf("Adding variable %s with initial value %d\n", inputName, inputVal);
addMap(map, inputName, inputVal);
}
}
int main(int argc, char** argv)
{
Mapping myVarMap;
char* varName;
int i;
getVariablesFromUser(&myVarMap);
// Display all the variables to show how to retrieve values
printf("%d variables added by user\n", myVarMap.NumEntries);
for(i=0; i<myVarMap.NumEntries; i++) {
LookUp_Entry *entry = &(myVarMap.mapping[i]);
char* name = entry->Name;
printf("Entry #%d: %s = %d\n", i+1, name, lookup(&myVarMap,name));
}
}
Save this in file lookup.c, then to compile it:
gcc lookup.c -o lookup
Here is sample run:
scott> lookup
Enter number of variables: 3
Init mapping for 3 variables
Enter variable #1 name and initial value: Bob 123
Adding variable Bob with initial value 123
Enter variable #2 name and initial value: Ted 999
Adding variable Ted with initial value 999
Enter variable #3 name and initial value: Sally 0
Adding variable Sally with initial value 0
3 variables added by user
Entry #1: Bob = 123
Entry #2: Ted = 999
Entry #3: Sally = 0
scott>
You cannot create variable names dynamically, however you can dynamically allocate memory using a function called 'malloc()'. You need to first understand pointers and then learn how to create and access memory during run-time.
As mentioned in the comments and answers of others, you cannot dynamically create variables in C.
However, you can follow this approach:
Dynamically read the characters for each line of n expressions (When the
length of input string is not fixed) For ex, Consider n =1 and the
input line is "a=10" Read each character 'a', '=' , '1' , '0'
Parse the string "a=10" to obtain the value 10. Dynamically allocate
memory to store this value 10.
Do this for all n input lines.
Here is the code to achieve this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Dynamically read the input string character by character: Taken from a SO answer
char *inputString(FILE* fp, size_t size){
//The size is extended by the input with the value of the provisional
char *str;
int ch;
size_t len = 0;
str = realloc(NULL, sizeof(char)*size);//size is start size
if(!str)return str;
while(EOF!=(ch=fgetc(fp)) && ch != '\n'){
str[len++]=ch;
if(len==size){
str = realloc(str, sizeof(char)*(size+=16));
if(!str)return str;
}
}
str[len++]='\0';
return realloc(str, sizeof(char)*len);
}
int main(void) {
int n,i,numindex;
char *variableline,*vartemp;
char keys[] = "1234567890";
//Read in the number of variables
printf("Enter n\n");
scanf("%d\n",&n);
printf("Enter %d lines\n",n);
//Allocate memory for these variables
int *variable_values = malloc(n*sizeof(int));
for(i=0;i<n;i++){
// Read the characters dynamically from the n input lines
variableline = inputString(stdin, 10);
//numindex - index where the number starts. For ex, in the string "a=12", numindex is the position of '1'
numindex = strcspn (variableline,keys);
//Read the number into vartemp
vartemp = malloc(strlen(variableline));
strncpy(vartemp, variableline+numindex, strlen(variableline) - numindex);
//Convert the string to number
*(variable_values+i) = atoi(vartemp);
}
printf("The variable values are:\n");
// All the variable values are stored in the dynamically created memory variable_values
for(i=0;i<n;i++)
printf("%d\n",variable_values[i]);
return 0;
}

Getting stuck in Dictionary Project in C

I prefer to create a Dictionary object and add 3 words to it.
My program has no compilation error but gets a run time error in the second for loop, is the problem in addNewWord function? Do I need pass a pointer to the DictionaryWord object ?
Please help me.
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<string.h>
typedef struct{
char* name;
char* mean;
} Words;
typedef struct{
Words* word;
int size;
} Dictionary;
Dictionary createNewDictionary();
Words createNewWord();
void addNewWord(Words newword, Dictionary dic);
Dictionary createNewDictionary(){
Dictionary dic;
dic.size = 0;
dic.word = (Words*)malloc(dic.size*sizeof(Words));
return dic;
}
Words createNewWord(){
Words newword;
newword.name = (char*)malloc(30*sizeof(char));
newword.mean = (char*)malloc(30*sizeof(char));
printf("============================\n");
printf("Enter word: ");
scanf("%[^\n]", newword.name);
fflush(stdin);
printf("\nEnter meaning: ");
scanf("%[^\n]", newword.mean);
return newword;
}
void addNewWord(Words newword, Dictionary dic){
dic.size++;
dic.word = (Words*)realloc(dic.word,dic.size*sizeof(Words));
strcpy(dic.word[dic.size-1].name, newword.name);
strcpy(dic.word[dic.size-1].mean, newword.mean);
}
int main(){
Dictionary d = createNewDictionary();
for (int i=0;i<3;i++){
addNewWord(createNewWord(), d);
}
return 0;
}
There are lots of problem with your code:
Given the longest word in English is around 30 characters, this size allocation is realistic for the word, but not for the defintion:
newword.name = (char*)malloc(30*sizeof(char));
newword.mean = (char*)malloc(30*sizeof(char));
This makes little obvious sense:
dic.size = 0;
dic.word = (Words*)malloc(dic.size*sizeof(Words));
you called malloc() on zero! You're only spared by your later realloc(). Even if intentional, it really deserves a comment.
This doesn't really work as fflush() is for output streams:
fflush(stdin);
see: How to clear input buffer in C? And whatever fix you use has to apply to both scanf() calls, not just one!
Per #Jarvis, this doesn't work:
dic.word = (Words*)realloc(dic.word,dic.size*sizeof(Words));
strcpy(dic.word[dic.size-1].name, newword.name);
strcpy(dic.word[dic.size-1].mean, newword.mean);
as you didn't allocate any space for name and mean in dic so you're copying into random memory.
Per #Jarvis, doesn't work:
void addNewWord(Words newword, Dictionary dic){
dic.size++;
dic.word = (Words*)realloc(dic.word,dic.size*sizeof(Words));
You're passing dic by value so inside addnewWord() you've a copy of dic so the original dic's size will be the same as it was before the call!
Memory leak:
addNewWord(createNewWord(), d);
you dropped your handle onto what createNewWord() returned so you can never free the memory it malloc()'d
You malloc() memory but provide no means to eventually free it.
Passing and returning structs by value is a disaster in a situation like this, as the data keeps getting copied. At the least it's inefficient, at worst its buggy like the size issue above. Rather than risk it, pretend they can only be passed and returned by pointer and you'll be playing it safe and get a better result.
Below is a rework of your code (in C) with fixes, style tweaks and an attempt at a consistent terminology. It also provides some minimal test code and the ability to free your data:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_WORD_LENGTH 30
#define MAX_DEFINITION_LENGTH 1024
typedef struct entry {
char *word;
char *definition;
} Entry;
typedef struct dictionary {
Entry *entries;
int num_entries, max_entries;
} Dictionary;
Dictionary *createNewDictionary() {
Dictionary *dictionary = malloc(sizeof(*dictionary));
dictionary->num_entries = 0;
dictionary->max_entries = 1;
dictionary->entries = calloc(dictionary->max_entries, sizeof(*dictionary->entries));
return dictionary;
}
void freeEntry(Entry *entry) {
free(entry->word);
free(entry->definition);
free(entry);
}
void freeDictionary(Dictionary *dictionary) {
for (--dictionary->num_entries; dictionary->num_entries >= 0; --dictionary->num_entries) {
// we can't call freeWord() here -- why.
free(dictionary->entries[dictionary->num_entries].word);
free(dictionary->entries[dictionary->num_entries].definition);
}
free(dictionary->entries);
free(dictionary);
}
void purgeInput() {
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
}
Entry *requestNewEntry() {
Entry *entry = malloc(sizeof(*entry));
entry->word = malloc(MAX_WORD_LENGTH);
entry->definition = malloc(MAX_DEFINITION_LENGTH);
printf("============================\n");
printf("Enter word: ");
scanf("%[^\n]", entry->word);
purgeInput();
printf("\nEnter definition: ");
scanf("%[^\n]", entry->definition);
purgeInput();
return entry;
}
void addNewEntry(Entry *entry, Dictionary *dictionary) {
if (dictionary->num_entries == dictionary->max_entries) {
dictionary->max_entries *= 2;
dictionary->entries = realloc(dictionary->entries, dictionary->max_entries * sizeof(*dictionary->entries));
// check if realloc returns NULL and if so, handle the error.
}
dictionary->entries[dictionary->num_entries].word = strdup(entry->word);
dictionary->entries[dictionary->num_entries].definition = strdup(entry->definition);
dictionary->num_entries++;
}
int main() {
Dictionary *d = createNewDictionary();
for (int i = 0; i < 3; i++) {
Entry *e = requestNewEntry();
addNewEntry(e, d);
freeEntry(e);
}
printf("\nRead: ");
for (int i = 0; i < d->num_entries; i++) {
printf("%s (%lu chars) ", d->entries[i].word, strlen(d->entries[i].definition));
}
printf("\n");
freeDictionary(d);
return 0;
}
CREATING A PUN DICTIONARY
> ./a.out
============================
Enter word: silkworm
Enter definition: Two silkworms had a race but ended up in a tie.
============================
Enter word: horse
Enter definition: A horse is a stable animal.
============================
Enter word: termite
Enter definition: A termite walks into a pub and asks, "Is the bar tender here?"
Read: silkworm (47 chars) horse (27 chars) termite (62 chars)
>
I see what's wrong with your code. First of all, you need to pass your Dictionary object by pointer to the function, addNewWord, and in the function addNewWord, you again need to allocate memory to each of the char* fields, name and mean, of the dic object. Here is the corrected code :
void addNewWord(Words newword, Dictionary *dic){
dic->size++;
dic->word = (Words*)realloc(dic->word, dic->size*sizeof(Words));
dic->word[dic->size-1].name = (char*)malloc(30*sizeof(char)); //added
dic->word[dic->size-1].mean = (char*)malloc(30*sizeof(char)); //added
strcpy(dic->word[dic->size-1].name, newword.name);
strcpy(dic->word[dic->size-1].mean, newword.mean);
}
Pass the dictionary's address as :
addNewWord(createNewWord(), &d);
and change the definition as well as prototype of the function as well :
void addNewWord(Words newword, Dictionary *dic)
Find the complete code here : http://pastebin.com/ZN69hevj

Resources