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

Time:01-07

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.

CodePudding user response:

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(" 9[^\n]", inputDef);

Check return value of input functions

if (scanf(" 9[^\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.

CodePudding user response:

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.

  • Related