I need help to write a function called find inside my program, which takes a key and a reference to an integer, fills in the reference with the appropriate value (if found), and returns 1 (true). If the key is not found, return 0 (false). You may assume that p already points to a valid location. So:
int find( char *key, int *p );
Can be called like this:
char *name = "Bob";
int data;
if( find( name, &data ))
printf( "Found %s. (S)he's %i\n\n", name, data );
else
printf( "\nCouldn't find %s\n\n", name );
This is the program I have:
#define TABLE_SIZE 7
#define NUM_INPUTS 7
int hash( char *s )
{
return strlen( s ) % TABLE_SIZE ;
}
typedef struct entry
{
char *key;
int val;
struct entry *next;
} entry;
entry* table[ TABLE_SIZE ] = { NULL };
void insert( char *s, int v )
{
int h = hash( s );
entry *t = (entry*) malloc( sizeof( entry ));
t->key = s;
t->val = v;
t->next = table[h];
table[h] = t;
}
int main()
{
char* keyList[] = { "Jaga", "Jesse", "Cos", "Kate", "Nash", "Vera",
"Bob" };
int valList[] = { 24, 78, 86, 28, 11, 99, 38 };
int i;
for( i=0; i<NUM_INPUTS; ++i )
insert( keyList[i], valList[i] );
/* Probably call function find right here */
return( 0 );
}
int find( char *key, int *p_ans )
{
}
Thank you.
Firstly you need to write a keycomp function prototype
int keycomp (struct data left,struct data right);
Return 0 for equals, -1 for L>R and 1 for R>L.
From the origin in your data space chain through comparing the test key to the stored keys.
Because you have a lot I control, ie knowing when a collision happens.
You could just try to store the test key if it goes straight in you know test key has no value stored. Should it collide you need to then do a keycomp against all colliding keys. Note key {2,rhubarb} may have the same hash as {37,dog}.
Remember to delete this newly created dummy test record.
Related
I'am working on a project for my programming class (teoretically in C++ but our professor isn't big fan of C++ solutions and C is better viewed by him). The project is to do simple queue with type given by user and the problem is with the following code:
#include <cstdlib>
#include <cstring>
#include <stdio.h>
typedef struct
{
int nKey;
int* pTab;
}Usertype;
Usertype* AllocateUsertype( );
void PrintUsertype( Usertype* pItem );
int main()
{
Usertype *pItem = AllocateUsertype();
printf( "nKey: %d, pTab: %d %d", pItem->nKey, pItem->pTab[0], pItem->pTab[1] );
pItem->nKey = 3;
PrintUsertype( pItem );
}
Usertype* AllocateUsertype( )
{
Usertype* pItem = NULL;
int* t = NULL;
t = (int*)malloc( 2*sizeof( int ) );
if( !t ) return NULL;
memset( t, 0, 2*sizeof( int ) );
Usertype Item = { 0,t };
pItem = &Item;
return pItem;
}
void PrintUsertype( Usertype* pItem )
{
printf( "nKey: %d, pTab: %d %d", pItem->nKey, pItem->pTab[0], pItem->pTab[1] );
}
When I allocate usertype it works well and the pItem is created as expected, but after I printf it it's seemes like pItem is no longer there and there's just garbage nKey number and there isn't any tab.
Is this problem because im allocating this data struct in memory wrongly and somehow t as a local variable for AllocateUsertype disapears at random moment? If yes can someone give me idea how to do it correctly?
As pointed out in the comments, the problem is that inside AllocateUsertype() you are returning a pointer to a local variable that won't exists anymore once the function returns.
The solution is to allocate a Usertype using malloc, just like you did for t, and then return its pointer.
Usertype* AllocateUsertype( )
{
Usertype* pItem = NULL;
pItem = (Usertype*)malloc(sizeof(Usertype));
if (!pItem) return NULL;
int* t = NULL;
t = (int*)malloc( 2*sizeof( int ) );
if( !t ) return NULL;
memset( t, 0, 2*sizeof( int ) );
pItem->nKey = 0;
pItem->pTab = t;
return pItem;
}
I'm reading and saving strings from a formatted file and for some reason I found out sscanf() changes testa_e->ident contents.
I have put some printf around and I found that the problem occurs right after sscanf(); I have also checked addresses of temp2, temp5 and testa_e by printing them but they are different.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define string 30
#define line 100
typedef const char *identifier;
struct nodo_id {
identifier ident;
struct nodo_id *next;
};
typedef struct nodo_id nodo_id;
nodo_id *testa_e = NULL;
void addent(const char *id_ent) {
if (testa_e == NULL) {
testa_e = malloc(sizeof(nodo_id));
testa_e->ident = id_ent;
testa_e->next = NULL;
} else {
nodo_id *curs = testa_e;
while (curs != NULL) {
curs = curs->next;
}
curs = malloc(sizeof(nodo_id));
curs->ident = id_ent;
curs->next = NULL;
}
}
int main() {
char temp[line];
char temp2[string];
char temp5[string];
fgets(temp, line, stdin);
while (strncmp(temp, "end", 3) != 0) {
if (strncmp(temp, "addent", 6) == 0) {
if (testa_e != NULL)
printf("\nbefore sscanf: %s\n", testa_e->ident);
sscanf(temp, "%s %s", temp5, temp2);
if (testa_e != NULL)
printf("\nafter sscanf: %s\n", testa_e->ident);
addent(temp2);
}
fgets(temp, line, stdin);
}
}
This code here reproduces the exact same problem; after launch write addent firstword and addent secondwordon terminal and right around sscanf it should show you that testa_e->ident content has changed, I'd like to know why and how to fix this, because I seriously have no idea...
In the function addent this loop
while(curs!=NULL){
curs=curs->next;
}
iterates until curs is equal to NULL.
Then you are changing the pointer
curs=malloc(sizeof(nodo_id));
curs->ident=id_ent;
curs->next=NULL;
The list itself was not changed. You changed only the local variable curs.
Change the loop the following way
while ( curs->next != NULL ){
curs = curs->next;
}
and then
curs->next = malloc( sizeof( nodo_id ) );
curs->next->ident = id_ent;
curs->next->next = NULL;
The other problem is that you are using pointers to a local array
char temp2[string];
//...
addent(temp2);
So the last that will be stored in the array will be pointed to by all nodes. You need to allocate dynamically memory for each string that will be stored in the list and assign the address to the data member ident. In this case you have to remove the qualifier const from its declaration.
Take into account that it is a bad idea to make a function depends on a global variable,
A better definition of the function addent can look the following way
struct nodo_id{
char *ident;
struct nodo_id* next;
};
typedef struct nodo_id nodo_id;
int addent( nodo_id **head, const char *id_ent )
{
nodo_id *new_nodo_id = malloc( sizeof( nodo_id ) );
int success = new_nodo_id != NULL;
if ( success )
{
new_nodo_id->ident = malloc( strlen( id_ent ) + sizeof( ( char )'\0' ) );
success = new_nodo_id->ident != NULL;
if ( ! success )
{
free( new_nodo_id );
}
else
{
strcpy( new_nodo_id->ident, id_ent );
new_nodo_id->next = NULL;
while ( *head != NULL ) head = &( *head )->next;
*head = new_nodo_id;
}
}
return success;
}
And the function can be called like
addent( &testa_e, temo2 );
Why in the function there is used the pointer to pointer to the head?
First of all if we want to change the original head we need to pass it by reference. Secondly in the loop
while ( *head != NULL ) head = &( *head )->next;
again the data member next of the last node is pointed to by the pointer. So we are changing not the local variable curs as in your implementation of the function but the data member next of the last node. So we are changing the list itself.
Pay attention to that defining such a typedef as
typedef const char* identifier;
is a bad practice.
The main problem is (besides the one #VladFromMoscow addressed in his answer), that in addent() you only store the pointer id_ent in your struct:
curs->ident=id_ent;
But that is nothing else but the address of temp2, so if you copy something else into temp2 by calling sscanf() you'll see the new value in testa_e->ident too.
Change the line form above to
curs->ident=strdup(id_ent);
to create a copy.
And don't forget to call free(curs->ident) when before you are freeing curs
I am new to C programming and I am trying to create a key value structure as in Perl Programming. I saw one solution like :-
struct key_value
{
int key;
char* value;
};
struct key_value kv;
kv.key = 1;
kv.value = "foo";
But I don't know how to access these values from this structure. Can someone enlight on this ?
Here is an example:
#include <stdio.h>
#include <stdlib.h>
struct key_value
{
int key;
char* value;
};
int main(void)
{
int number_of_keys = 2;
struct key_value *kv = malloc(sizeof(struct key_value) * number_of_keys);
if (kv == NULL) {
perror("Malloc");
exit(EXIT_FAILURE);
}
kv[0].key = 8;
kv[0].value = "Test 8 key!";
kv[1].key = 6;
kv[1].value = "Test 6 key!";
printf("Key = %d\nKey value = %s\n", kv[0].key, kv[0].value);
printf("Key = %d\nKey value = %s\n", kv[1].key, kv[1].value);
free(kv);
return 0;
}
What you are missing is a collection. Most languages have a data type called a dictionary or a map or an associative array or some variation thereof. C does not have a data structure of this type; in fact, the only collection type you have built in to C is the array. So, if you want something where you can supply a key and get the value, you have to roll your own or find one on the Internet. The latter is probably preferable because you are likely to make mistakes and produce a slow data structure if you roll your own (especially if you are a beginner).
To give you a flavour of what you'll end up with, here's a simple example:
You'll need something to represent the collection; call it a ListMap for now:
struct ListMap;
The above is called an incomplete type. For now, we are not concerned with what's in it. You can't do anything with it except pass pointers to instances around.
You need a function to insert items into your collection. Its prototype would look something like this:
bool listMapInsert(struct ListMap* collection, int key, const char* value);
// Returns true if insert is successful, false if the map is full in some way.
And you need a function to retrieve the value for any one key.
const char* listMapValueForKey(struct ListMap* collection, int key);
You also need a function to initialise the collection:
struct ListMap* newListMap();
and to throw it away:
void freeListMap(struct ListMap* listMap);
The hard bit is implementing how those functions do what they do. Anyway, here's how you would use them:
struct ListMap* myMap = newListMap();
listMapInsert(myMap, 1, "foo");
listMapInsert(myMap, 1729, "taxi");
listMapInsert(myMap, 28, "perfect");
char* value = listMapValueForKey(myMap, 28); // perfect
freeListMap(myMap);
Here's a simple implementation. This is just for illustration because I haven't tested it and searching for entries increases linearly with the number of entries (you can do much better than that with hash tables and other structures).
enum
{
listMapCapacity = 20
};
struct ListMap
{
struct key_value kvPairs[listMapCapacity];
size_t count;
};
struct ListMap* newListMap()
{
struct ListMap* ret = calloc(1, sizeof *ret);
ret->count = 0; // not strictly necessary because of calloc
return ret;
}
bool listMapInsert(struct ListMap* collection, int key, const char* value)
{
if (collection->count == listMapCapacity)
{
return false;
}
collection->kvPairs[count].key = key;
collection->kvPairs[count].value = strdup(value);
count++;
return true;
}
const char* listMapValueForKey(struct ListMap* collection, int key)
{
const char* ret = NULL;
for (size_t i = 0 ; i < collection->count && ret == NULL ; ++i)
{
if (collection->kvPairs[i].key == key)
{
ret = kvPairs[i].value;
}
}
return ret;
}
void freeListMap(struct ListMap* listMap)
{
if (listMap == NULL)
{
return;
}
for (size_t i = 0 ; i < listMap->count ; ++i)
{
free(listMap->kvPair[i].value);
}
free(listMap);
}
typedef struct key_value
{
int key;
char* value;
}List;
struct key_value k1;
struct key_value k2;
struct key_value k3;
k1.key = 1;
k1.value = "foo";
k2.key = 2;
k2.value = "sec";
k3.key = 3;
k3.value = "third";
You will need to create N times the struct and give them values the way you did the first one. Or create array with N structs and iterate assign it values with a loop.
Array:
List arr[29];
int i;
for(i = 0;i<=28;i++){
arr[i].key = i;
arr[i].value = "W/e it needs to be";
}
The functionality you are looking for needs your own implementation in C; e.g. an array of your struct-type.
Here is an example of how to read the value for a key, without knowing anything about at which array-index the key will be found.
I have the keys numbered backward in order to illustrate that.
Note that more sophisticated API definitions are needed for special cases such as non-existing key; I just blindly return the last entry to keep things easy here.
#include <stdio.h>
#define MAPSIZE 30
struct key_value
{
int key;
char* value;
};
struct key_value kvmap[MAPSIZE];
void initmap(void)
{
int i;
for(i=0; i<MAPSIZE; i++)
{
kvmap[i].key=MAPSIZE-i-1;
kvmap[i].value="unset";
}
kvmap[0].value="zero";
kvmap[1].value="one";
kvmap[2].value="two";
kvmap[3].value="three";
kvmap[4].value="four";
kvmap[5].value="five";
kvmap[6].value="six";
kvmap[7].value="seven";
kvmap[8].value="eight";
kvmap[24].value="find this"; // it has the key "5"
}
char* readmap(int key)
{
int i=0;
while ((i<MAPSIZE-1) && (kvmap[i].key!=key))
{ printf("Not in %d\n", i);
++i;}
// will return last entry if key is not present
return kvmap[i].value;
}
int main(void)
{
initmap();
printf("%s\n", readmap(5));
return 0;
}
"I have to store 30 key/value pair"
Create an array of struct e.g., key_value.
struct key_value
{
int key;
char* value;
};
struct key_value kv[30];
kv[0].key = 1;
kv[0].value = "foo";
printf("%s", kv[0].value);
You can loop through to assign values to keys and values.
Access to whatever is in kv is simple.
int i = kv[0].key`;// copy value of k[0].key to i
char *v = kv[0].value; // copy value of k[0].value to v;
Your code already have the method to acess the values.
kv.key = 1
kv.value = "foo"
To get the values assigned is simple
kv.key
kv.value
It is a simple struct, if you wanna something like python dict you will need to implement a hash struct which will be more complicated.
I am trying to create a program that receives from the user 12 song titles and then forms a set list in a random order. I have used the gets() function and memory allocation so that the input is placed into an array like this:
argv[0] = song1, argv[1] = song2, argv[2] = song3 (etc.).
There seems to be the common segmentation fault error when inputting the actual songs and then running it through the randomize and createSetList() functions. However, if one were to scrap the memory allocation and hard code instead it would work fine. By this I mean something like:
char *input[ SONG ] =
{ "song1", "song2", "song3", "song4",
"song5", "song6", "song7", "song8",
"song9", "song10", "song11", "song12", "song13" };
Although, my purpose is to have the user input the song titles during run time. What is the reason for a segmentation fault error?
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#define SONG 13
#define SETSIZE 5
// prototypes
void randomize( unsigned int wDeck[ SONG ] );
void createSetList( unsigned int wDeck[ SONG ], char *wFace[] );
int main( void ){
printf("Please enter the songs you want to play!\n");
printf("I will create the set list and randomize it for you!\n");
char input[100];
char *argv[ SONG ];
char *token;
/*memory allocation for inputting song titles into a single array*/
/*****memory allocation code starts here********/
gets(input);
token = strtok(input, " ");
int i=0;
while( token != NULL ) {
argv[i] = malloc(strlen(token) + 1);
strncpy(argv[i], token, strlen(token));
i++;
token = strtok(NULL, " ");
}
argv[i] = NULL; //argv ends with NULL
/***memory allocation code ends here*****/
unsigned int setList[ SONG ] = { 0 };
srand( time( NULL ) ); // seed random-number generator
randomize( setList ); // shuffle the list
createSetList( setList, argv ); // create the setlist
} //end of main
/*SHUFFLE FUNCTION*/
void randomize( unsigned int wDeck[ SONG ] ){
size_t column;
size_t c;
for ( c = 1; c <= SETSIZE; ++c ) {
do {
column = rand() % SONG;
} while( wDeck[ column ] != 0 );
wDeck[ column ] = c;}}
/* Create Set List Function */
void createSetList( unsigned int wDeck[ SONG ], char *wFace[] ){
size_t c;
size_t column;
for ( c = 1; c <= SETSIZE; ++c ) {
for ( column = 0; column < SONG; ++column ) {
if ( wDeck[ column ] == c ) {
printf( "%s\n", wFace[ column ]);
}}}}
In your code,
strncpy(argv[i], token, strlen(token));
usage is wrong. You need to copy the terminating null byte also.
As we can see from the man page of strncpy()
The strncpy() function is similar, except that at most n bytes of src are copied.
Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.
As mentioned in the comments my Mr # chqrlie and explained in the nice article by #Keith Thompson, you should not be using strncpy(). To be on safer side, you can make use of strdup() to avoid the overhead (and pitfalls) of malloc()+ strcpy().
Pseduo-code
argv[i] = strdup(token);
will do the job in an efficient way. Remember, you need to still free() the returned pointer by strdup().
ok, heres my code. I'm trying to pass an array of pointers to a structure to a function.
I need to dynamically allocate each structure and put a pointer to that structure in the array.
When I malloc the second time thru it gets a heap error.
HELP
#define MAXSTRUCTS 50
#define MAXBUFF 100
typedef struct {
char fullName[41];
char address[41];
char cityState[41];
char zipcode[11];
} Persons;
int readData(Persons *structPtrs[]);
int main(void) {
int totalStructs;
Persons *structPtrs[MAXSTRUCTS];
totalStructs = 0;
structPtrs[0] = NULL;
totalStructs = readData(structPtrs);
}
int readData(Persons *strptr[]) {
int tStructs = 0;
int recs;
char inRecord[MAXBUFF];
Persons *tmpPtr;
tStructs = 0;
for (recs=0; recs < MAXSTRUCTS; recs++) {
if (gets(inRecord) != NULL) {
strptr[recs] = (Persons *)malloc( sizeof(Persons));
tmpPtr = strptr[recs];
strncpy(tmpPtr->fullName,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->address,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->cityState,inRecord,MAXBUFF);
gets(inRecord);
strncpy(tmpPtr->zipcode,inRecord,MAXBUFF);
strptr[recs] = tmpPtr;
tStructs++;
}
else {
if ( recs = 0 ) {
exit (0);
}
recs=MAXSTRUCTS;
}
}
return(tStructs);
}
You are doing everything right in regard of passing an array of pointers and allocating memory. What leading to a heap corruption is incorrect usage of strncpy function. The arrays where you are trying to copy data to are slightly smaller than MAXBUFF in all cases. To fix this, you have to specify the size of destination array instead of MAXBUFF. For example, instead of:
strncpy(tmpPtr->fullName,inRecord,MAXBUFF);
... do (assuming that buffer is already filled with \0 symbols):
strncpy(tmpPtr->fullName,inRecord, sizeof(tmpPtr->fullName) - 1);
Also, using gets function is not recommended as well as it could easily lead to buffer overruns. Try using fgets instead.
Here is your modified example that works:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAXSTRUCTS 2
#define MAXBUFF 100
typedef struct {
char fullName[41];
char address[41];
char cityState[41];
char zipcode[11];
} Persons;
int readData(Persons *structPtrs[]);
int main ()
{
int totalStructs;
int recs;
Persons *structPtrs[MAXSTRUCTS];
totalStructs = 0;
structPtrs[0] = NULL;
totalStructs = readData(structPtrs);
for(recs = 0; recs < totalStructs; ++recs) {
printf ("Record #%d - %s\n", recs + 1, structPtrs[recs]->fullName);
}
return 0;
}
int readData(Persons *strptr[])
{
int tStructs = 0;
int recs;
char inRecord[MAXBUFF];
Persons *tmpPtr;
tStructs = 0;
for (recs=0; recs < MAXSTRUCTS; ++recs) {
memset (inRecord, 0, sizeof(inRecord));
if (fgets(inRecord, sizeof (inRecord) - 1, stdin))
{
strptr[recs] = (Persons *)malloc(sizeof(Persons));
tmpPtr = strptr[recs];
memset (tmpPtr, 0, sizeof(Persons));
strncpy(tmpPtr->fullName,inRecord,sizeof(tmpPtr->fullName) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->address,inRecord,sizeof(tmpPtr->address) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->cityState,inRecord, sizeof(tmpPtr->cityState) - 1);
fgets(inRecord, sizeof (inRecord) - 1, stdin);
strncpy(tmpPtr->zipcode,inRecord, sizeof (tmpPtr->zipcode) - 1);
strptr[recs] = tmpPtr;
tStructs++;
} else {
if ( recs = 0 ) {
exit (0);
}
recs=MAXSTRUCTS;
}
}
return(tStructs);
}
int readDataToRecord( Persons *eachEntry[] ) {
int numEntries = 0 ;
Persons *tempPtr ;
for( int i=0 ; i < NUM_OF_RECORDS; ++i ) {
eachEntry[i] = ( Record * ) malloc( sizeof( Record ) ) ;
memset( eachEntry[i], 0, sizeof( Record ) ) ;
tempPtr = eachEntry[i] ;
fgets( tempPtr->firstName, sizeof( tempPtr->firstName ), stdin ) ;
fgets( tempPtr->secondName, sizeof( tempPtr->secondName), stdin ) ;
eachEntry[i] = tempPtr ;
++numEntries ;
}
return numEntries ;
}
This would also efficiently do the job. Once you have new record, you would any how have the memory allocated for each of its member. So you can directly fgets to that variable.
#Vlad : Please let me know if I am wrong.