Adding strings and values to a hash table in C [duplicate] - c

This question already has answers here:
Why does a pointer to array need to be cast before being passed as parameter to a function with array type argument?
(3 answers)
Closed last month.
I'm trying to add a persons and number to a hash table, but when I'm adding these values I get the incompatible pointer types passing 'char *[20]' to parameter of type 'char *' error.
I'm also getting an EXC_BAD_ACCESS (code=1, address=0x140) when assigning the customer_number to the index.
typedef struct
{
char *first_name[20];
int customer_number;
} Customer;
Customer *list[10];
int hash_table[10];
void insert(char *first_name, int customer_number)
{
int index = calculate_hash(customer_number);
list[index]->customer_number = customer_number;
strcpy(list[index]->first_name, first_name);
hash_table[index]=customer_number;
}
int main(void)
{
insert("Chris", 9999);
return 0;
}
When the insert is passed a first name and phone_number, I want these to be added to the hash.

There are a number of issues here. You need to look again at pointers and buffer overflows...
#define CUSTOMER_NAME_MAX_LEN 20
typedef struct
{
char first_name[CUSTOMER_NAME_MAX_LEN + 1];
int customer_number;
} Customer;
Customer list[10];
int hash_table[10];
int calculate_hash(int customer_number) {
return 3;
}
void insert(char *first_name, int customer_number)
{
int index = calculate_hash(customer_number);
list[index].customer_number = customer_number;
list[index].first_name[CUSTOMER_NAME_MAX_LEN] = 0; // Avoid buffer overflow.
strncpy(list[index].first_name, first_name, CUSTOMER_NAME_MAX_LEN);
hash_table[index]=customer_number;
}
int main(void)
{
insert("Chris", 9999);
printf("%s %i\n", list[3].first_name, list[3].customer_number);
return 0;
}
// Outputs Chris 9999

Related

passing 'person [4]' to parameter of incompatible type 'person'

Here I'm trying to write a c programming below,Here I created a data type person which has two arguments name and number (creating a name of the candidate and votes they have recieved), and when prompt for input,if user enters the name in the array of person data_type and number corresponds to that number should increase,but I got stuck in this error below.
#include<stdio.h>
#include<cs50.h>
#include<string.h>
//Making person variable
typedef struct
{
string name;
int number;
}
person;
int update_vote(string name,person arr);
int main(void)
{
person cand[4];
cand[0].name="Brian";
cand[1].name="David";
cand[2].name="Obama";
cand[3].name="Biden";
cand[0].number=0;
cand[1].number=0;
cand[2].number=0;
cand[3].number=0;
//print the candidate names on the screen
float len=sizeof(cand)/sizeof(cand[0]);
int yu =(int) len;
printf("Candidates Who are participating:");
printf("\n");
for (int i=0;i<yu;i++)
{
printf("%i.%s ",i+1,cand[i].name);
}
printf("\n");
//prompt for voters and take votes and update
int voters=get_int("Enter the number of voters:");
for (int j=0;j<voters;j++)
{
string vote=get_string("Enter your vote:");
int update=update_vote(vote,cand);
if (update!=-1)
{
cand[update].number++;
}
else{
printf("Invalid name entered");
}
}
printf("%d",cand);
}
int update_vote(string name,person arr)
{
float len=sizeof(arr)/sizeof(arr[0]);
int yu =(int) len;
for(int i=0;i<yu;i++)
{
if (strcmp((name,arr[i].name)==0))
{
return i;
}
}
return -1;
}
But got stuck in figuring out why the error is occuring below
error: passing 'person [4]' to parameter of incompatible type 'person'
int update=update_vote(vote,cand);
The error is because you are passing person* where person is expected as an argument.
You should change the type of argument so that it can receive (a pointer to) an array.
Also note that sizeof cannot be used to determing the number of elements of arrays passed as arguments. You should pass the number of elements separately.
Another point is that printf("%d",cand); will invoke undefined behavior because data having wrong type is passed. %d expects int. If you want to print a pointer, you should cast it to void* and use %p format specifier.
Try this:
#include<stdio.h>
#include<cs50.h>
#include<string.h>
//Making person variable
typedef struct
{
string name;
int number;
}
person;
int update_vote(string name,person* arr,int arrSize); /* fix arguments */
int main(void)
{
person cand[4];
cand[0].name="Brian";
cand[1].name="David";
cand[2].name="Obama";
cand[3].name="Biden";
cand[0].number=0;
cand[1].number=0;
cand[2].number=0;
cand[3].number=0;
//print the candidate names on the screen
float len=sizeof(cand)/sizeof(cand[0]);
int yu =(int) len;
printf("Candidates Who are participating:");
printf("\n");
for (int i=0;i<yu;i++)
{
printf("%i.%s ",i+1,cand[i].name);
}
printf("\n");
//prompt for voters and take votes and update
int voters=get_int("Enter the number of voters:");
for (int j=0;j<voters;j++)
{
string vote=get_string("Enter your vote:");
int update=update_vote(vote,cand,yu); /* pass the number of elements */
if (update!=-1)
{
cand[update].number++;
}
else{
printf("Invalid name entered");
}
}
printf("%p",(void*)cand); /* use correct way to print a pointer */
}
int update_vote(string name,person* arr,int arrSize) /* fix arguments */
{
int yu =arrSize; /* use the passed size instead of sizeof */
for(int i=0;i<yu;i++)
{
if (strcmp((name,arr[i].name)==0))
{
return i;
}
}
return -1;
}
Because person cand[4]; , when you use " int update=update_vote(vote,cand);" , it means 'person *' that it's pointer.

Passing struct into function

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 100000
typedef struct {
int day;
int month;
int year;
} DATE;
typedef struct {
char name[100];
int age;
float hrlyWage;
float hrsWorked;
float regPay;
float otPay;
float totalPay;
DATE payDate;
} PAYRECORD;
int newRecord(struct PAYRECORD record[], int index){
//set name to \0 so it can work as string
record[index].name = {'\0'};
index++;
return index;
}
int main(){
char menuChoice = 'X';
struct PAYRECORD record[SIZE];
int index = 0;
while (menuChoice != 'Q'){
system("pause");
system("cls");
menuChoice = runMenu();
switch (menuChoice){
case 'A':
index = newRecord(record, index);
}
}
}
main sets up an array of structs the gets passed into newRecord, and the goal is to make it so that I can input the data here and then return the new index to keep track of my array of structs. However something is going wrong where my program doesn't seem to be recognizing newRecord as a function, which ends up throwing the whole program off.
I get syntax errors for all the functions inside of newRecord, though I beleive it's because, as I mentioned, the program seems to be unable to recognize newRecord as a User defined Function.
Use of struct PAYRECORD is wrong since there is no such type. You only have a typedef named PAYRECORD.
If you want to be able to use struct PAYRECORD as well as just PAYRECORD, change the definition of the struct to:
typedef struct PAYRECORD {
char name[100];
int age;
float hrlyWage;
float hrsWorked;
float regPay;
float otPay;
float totalPay;
DATE payDate;
} PAYRECORD;
If that's not your goal, change the use of struct PAYRECORD by just PAYRECORD.
Also, the line:
record[index].name = {'\0'};
in newRecord is not correct. You cannot assign to an array like that. Change it to:
record[index].name[0] = '\0';
The struct PAYRECORD does not exist, the compiler has no idea how big that is.
Note that PAYRECORD is a typedef to an anonymous struct. So your function
should look like this:
int newRecord(PAYRECORD record[], int index){
//set name to \0 so it can work as string
record[index].name[0] = 0;
index++;
return index;
}
Also note that {'\0'}; works only when initializing a array when you declare
it:
char arr1[10] = { '\0' }; // OK
char arr2[10];
arr2 = { '\0' }; // NOT OK
// error: expected expression before ‘{’ token
// a = { '\0' };
// ^
And when writing functions that take arrays as an argument, you should also pass
the size of the array.
int newRecord(PAYRECORD record[], int index, size_t len){
if(record == NULL)
return -1; // error, NULL passed
if(index >= len)
return -1; // error, cannot access array
record[index].name[0] = 0;
index++;
return index;
}
And then you can call it from main like this:
PAYRECORD record[SIZE];
...
int index = 0;
if(newRecord(record, index, sizeof record / sizeof *record) != index)
{
// error handling
}
This makes the code more robust. You always have to check the array boundaries,
otherwise you might read/write out of bounds. And also check that NULL has not
been passed as well, if you dereference NULL, your program will crash with
segfault.
Also, the parameter to newRecord could be a PAYARRAY, not an array directly; based on declaring
typedef struct { } PAYRECORD, PAYARRAY[SIZE];
int newRecord(PAYARRAY record, int index) {...}
int main(){
...
PAYARRAY record;
...
case 'A':
index = newRecord(&record, index);
}
The compiler should be converting the PAYARRAY or PAYRECORD[] argument to a PAYRECORD * pointing to the first element, so use of the '&' is indicated for the function call.

How do I correctly find out, what size the array of structs is? [duplicate]

This question already has answers here:
How to find the size of an array (from a pointer pointing to the first element array)?
(17 answers)
Closed 5 years ago.
I have the following minimal example and I don't get, why my struct sizes are wrong. I'm expecting the output to be 50, instead I get 1. What am I doing wrong?
#include <stdio.h>
#include <stdlib.h>
typedef struct prod {
char *x;
} prod_t;
typedef struct obj {
prod_t *things;
} obj_t;
#define LARGE_BUF 100
#define CHAR_BUF 20
obj_t *func1(obj_t *t) {
t->things = malloc(sizeof(prod_t) * LARGE_BUF);
for (uint16_t i = 0; i < 50; i++) {
t->things[i].x = malloc(sizeof(char) * CHAR_BUF);
t->things[i].x = "hello";
}
return t;
}
int main(int argc, char **argv) {
obj_t *var = malloc(sizeof(obj_t));
var = func1(var);
printf("%lu\n", sizeof(var->things)/sizeof(var->things[0]));
return 0;
}
Since I don't have the number of entries, the function generated for me (it's 50 now, but it could change dynamically), how do I free(..) this up?
Is the only option to introduce a field in the struct, to keep track of the actual array size?
Yes you will need to add another member to the struct. For example a string wrapper type keeps track of the number of characters in it:
typdef struct {
char *base;
size_t n;
} string;
Notice n is of size_t, not int.

EXC_BAD_ACCESS using QSort on an Array of Chars within Structs in C

I have searched through many of the answers on here and have implemented a few changes based on that, but am getting a EXC_BAD_ACCESS error when calling the qsort function. My IDE is pointing to the return in my qsort compare function as the problem. I know I am allocating memory properly for all the elements as I can print the strings with no problem if I omit the call to qsort. Could someone point me in the right direction?
My structs, to see how deep I am navigating:
typedef struct {
unsigned int siteId;
unsigned int tableTypeId;
unsigned int surMatId;
unsigned int strucMatId;
char *streetAve;
unsigned int neighbourhoodId;
char *neighbourhoodName;
unsigned int ward;
char *latitude;
char *longitude;
} Entries;
typedef struct {
int size;
Entries **entry;
} PicnicTable;
typedef struct {
Table *tableTypeTable;
Table *surfaceMaterialTable;
Table *structuralMaterialTable;
NeighbourHoodTable *neighborhoodTable;
PicnicTable *picnicTableTable;
} DataBase;
extern DataBase *DB;
Entries **ent = DB->picnicTableTable->entry;
qsort(ent,DB->picnicTableTable->size-1, sizeof(Entries*), cmpfunc); typedef struct {
unsigned int siteId;
unsigned int tableTypeId;
unsigned int surMatId;
unsigned int strucMatId;
char *streetAve;
unsigned int neighbourhoodId;
char *neighbourhoodName;
unsigned int ward;
char *latitude;
char *longitude;
} Entries;
typedef struct {
int size;
Entries **entry;
} PicnicTable;
typedef struct {
Table *tableTypeTable;
Table *surfaceMaterialTable;
Table *structuralMaterialTable;
NeighbourHoodTable *neighborhoodTable;
PicnicTable *picnicTableTable;
} DataBase;
extern DataBase *DB;
This is what the call looks like:
Entries **ent = DB->picnicTableTable->entry;
qsort(ent,DB->picnicTableTable->size-1, sizeof(Entries*), cmpfunc);
And the compare function is:
int cmpfunc(const void *a, const void *b) {
Entries *left = *(Entries**)a;
Entries *right = *(Entries**)b;
return strcmp(left->neighbourhoodName, right->neighbourhoodName);
}
The picnicTableTable, and Entry are initialized after this malloc:
DB->picnicTableTable = malloc(sizeof(PicnicTable));
DB->picnicTableTable->entry = malloc(numEntries*sizeof(Entries)+1);
DB->picnicTableTable->size = numEntries;
while ((c=fgetc(IN)) != EOF) {
if (c == ',' && row > 0) {
switch (column) {
case 0: neighbourhoodName = copyToChar(buff, begin, i);
...
}
copyToChar take a slice of the buffer and allocates memory then returns a pointer to a value that I assign:
char * copyToChar(const char * buff, int begin, int end) {
char *temp = malloc(end - begin + 1);
int j = 0;
for (int i = begin; i < end; i++, j++)
temp[j] = buff[i];
temp[j] = '\0';
return temp;
}
And the array is populated after I iterate through each row in a file (this is just one entry):
DB->picnicTableTable->entry[row]->neighbourhoodName = malloc(strlen(neighbourhoodName)*sizeof(char)+1);
The values of a->neighbourhoodName are NULL, which confuses me. Doesn't qsort pass two values from the array to the compare function?
Thanks for your time!
Beware. You declare entry to be a pointer to pointers (pointing to first element of an array of pointers)
typedef struct {
int size;
Entries **entry;
} PicnicTable;
but initialize it as a mere dynamic array, that is a pointer to first element of an array of Entrys in:
DB->picnicTableTable->entry = malloc(numEntries*sizeof(Entries)+1);
If you want an array of pointers to speed up qsort, you should build it separately:
typedef struct {
int size;
Entries *entry;
Entries **pentry;
} PicnicTable;
DB->picnicTableTable->entry = malloc(numEntries*sizeof(Entries)+1);
DB->picnicTableTable->pentry = malloc(numEntries*sizeof(&Entries)+1);
for (int i=0; i<=numEntries; i++) { // initialize the array of pointers
pentry[i] = entry + i;
}
Currently the definition of cmpfunc is not coherent with your initialization of DB->picnicTableTable->entry.

Segmentation Fault in C

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));
}

Resources