Segmentation Fault when returning integer - c

I recently joined Stackoverflow community because I had to ask this question. I've been searching for possible explanations and solutions on the website but so far nothing enlightened me as I wanted. My error is probably caused by a very specific line of code. I'm trying to create a function that reads an array of struct votes, (struct contains integer member number, char *category, char *nominee) and copies all the votes that contain the same number and category to another array of struct. Basically to show all the repeated votes.
typedef struct
{
int member;
char *categ;
char *nom;
}Vote
Vote vote(int member, char *categ, char *nom)
{
Vote result;
result.member = member;
result.categ = categ;
result.nom = nom;
return result;
}
int votes_count(Vote *v, int n, Vote *v1)
{
int result = 0;
int *index = malloc(sizeof(int) * 1000);
int a = 0;
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < n; ++j)
{
if (a == 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0)
{
v1[result++] = vote(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
for (int b = 0; b < a; ++b)
{
if( a > 0 && v[i].member == v[j].member && strcmp(v[i].categ, v[j].categ) == 0 && j != index[b])
{
v1[result++] = voto(v[j].member, str_dup(v[j].categ), str_dup(v[j].nom));
index[a++] = j;
}
}
}
}
return result;
}
Afterwads, it returns the number of elements of new array that contains all repetitions. I want to use an array of ints to save all line indexes so that the function doesn't read and copy the lines it already accounted.
Sorry if the code is hard to understand, if needed I can edit to be more understandable. Thanks for any answears.
P.S: I'm portuguese, sorry in advance for grammar mistakes

if your only intention is to harvest the duplicates, you only need to compare to the elements that came before an element
you don't need the index[] array
For simplicity, I used two integer arrays, you should change them to your struct arrays, also change the compare function.
unsigned fetchdups(int orig[], int dups[], unsigned count)
{
unsigned this, that, ndup=0;
for (this=1; this<count; this++){
for (that=0; that<this; that++){
/* change this to your compare() */
if(orig[that] == orig[this]) break;
}
if (this == that) continue; /* no duplicate */
dups[ndup++] = this;
}
return ndup;
}

Related

How to write a C function to detect cycles in a void* array

I'm trying to implement the C function int contains_cycle(void *const array[], size_t length) to detect if there are any "cycles" in an array of void pointers. All elements of this array either point to an adress of this array or to NULL. Pointers still quite overwhelm me and I've got no idea where to start.
Just to clarify, what I mean by cycle, here are some examples. Just for illustration the first element's adress is always at adress 0x1 and pointers have the size of 1 byte.
{NULL, 0x3, 0x2} -> should return 1, cycle between array[1] and array [2]
{0x2, 0x3, 0x1} -> should return 1, cycle between all the elements
{0x2, 0x3, NULL} -> should return 0, no cycle
I would appreciate any help and if my goal is still not quite clear, I am happy to explain more.
My idea would be iterating over the array and somehowe "follow" the pointers to see if I end up on the starting point again. If that's the case for at least one element, I've found a cycle.
Yes. You just "follow the pointers", but you need to know whether you followed to a pointer that you already hit.
So my idea to solve your problem is to make a struct that contains an index instead of a pointer because this makes life so much easier...
typedef struct {
size_t toIndex;
bool marked;
} Entry;
Then I create a new array of all these entries with the same length as the original. I calculate the toIndex that I store in the struct using the current element's pointer minus the address of the array's beginning.
bool contains_cycle(void* array[], size_t length) {
Entry newArray[length];
for(size_t i = 0; i < length; ++i) {
size_t toIndex = ((size_t) array[i] - (size_t) &array[0] ) / sizeof *array;
newArray[i] = (Entry) { toIndex, false };
}
After that I look for the first index where the pointer is not null
size_t index = 0;
for(size_t i = 0; i < length; ++i) {
if (array[i] == NULL) continue;
index = i;
break;
}
Now, if we just let a loop run until we hit some index that is out of bounds (this will implicitly detect if we hit a NULL-element) and check if the current element is already marked. if so, return true.
while(index < length) {
if (newArray[index].marked) return true;
newArray[index].marked = true;
index = newArray[index].toIndex;
}
If the loop exits without a return you know that the loop did not start from there. You now need to check if the loop started from any other index that you haven't marked yet. But I'm too lazy to implement that now. Go try this yourself :)
For now I just return false
return false;
}
I tried to replicate your examples in the main function.
#include <stdio.h>
#include <stdbool.h>
typedef struct {
size_t toIndex;
bool marked;
} Entry;
bool contains_cycle(void* array[], size_t length) {
Entry newArray[length];
for(size_t i = 0; i < length; ++i) {
size_t toIndex = ((size_t) array[i] - (size_t) &array[0] ) / sizeof *array;
newArray[i] = (Entry) { toIndex, false };
}
size_t index = 0;
for(size_t i = 0; i < length; ++i) {
if (array[i] == NULL) continue;
index = i;
break;
}
while(index < length) {
if (newArray[index].marked) return true;
newArray[index].marked = true;
index = newArray[index].toIndex;
}
return false;
}
int main() {
void* example1[3];
void* example2[3];
void* example3[3];
example1[0] = NULL;
example1[1] = &example1[2];
example1[2] = &example1[1];
example2[0] = &example2[1];
example2[1] = &example2[2];
example2[2] = &example2[0];
example3[0] = &example3[1];
example3[1] = &example3[2];
example3[2] = NULL;
printf("%d ", contains_cycle(example1, 3));
printf("%d ", contains_cycle(example2, 3));
printf("%d ", contains_cycle(example3, 3));
}
I'm certain that there can be a faster way but the one above does work with your examples

How to initialize a field in a struct from another struct? C

So im new to C programming and my assignment is to write a function(Max_way) that prints the driver who had the total of longest trips.
im using these 2 structs:
#define LEN 8
typedef struct
{
unsigned ID;
char name[LEN];
}Driver;
typedef struct
{
unsigned T_id;
char T_origin[LEN];
char T_dest[LEN];
unsigned T_way;
}Trip;
and a function to determine the total trips of a certain driver:
int Driver_way(Trip trips[], int size, unsigned id)
{
int km=0;
for (int i = 0; i < size; i++)
{
if (id == trips[i].T_id)
{
km = km + trips[i].T_way;
}
}
return km;
}
but when im trying to print the details of a specific driver from an array of drivers, i receive the correct ID, the correct distance of km, but the driver's name is not copied properly and i get garbage string containing 1 character instead of 8.
i've also tried strcpy(max_driver.name,driver[i].name) with same result.
void Max_way(Trip trips[], int size_of_trips, Driver drivers[], int size_of_drivers)
{
int *km;
int max = 0;
Driver max_driver;
km = (int*)malloc(sizeof(int) * (sizeof(drivers) / sizeof(Driver)));
for (int i = 0; i < size_of_drivers; i++)
{
km[i] = Driver_way(trips, sizeof(trips), drivers[i].ID);
for (int j = 1; j < size_of_drivers; j++)
{
if (km[j] > km[j - 1])
{
max = km[j];
max_driver.ID = drivers[i].ID;
max_driver.name = drivers[i].name;
}
}
}
printf("The driver who drove the most is:\n%d\n%s\n%d km\n", max_driver.ID, max_driver.name, max);
}
any idea why this is happening?
Note that one cannot copy a string using a simple assignment operator; you must use strcpy (or similar) as follows:
if (km[j] > km[j - 1]) {
max = km[j];
max_driver.ID = drivers[i].ID;
strcpy(max_driver.name,drivers[i].name);
}
Also note that since you were using ==, this was not even a simple assignment, put a comparison. Changing to == likely fixed a compile-time error, but it did NOT give you what you want.

How can I arrange the structs in an array of structs in an ascending order?

I am sorry if this sounds confusing, I will try to be as clear as possible. I have an array of structs, where the array stores a struct that I have defined as a Business Card. However, before adding any new business cards into the array, I have to store the structs in ascending order based on the integer value of the Employee ID.
Here is the struct:
typedef struct{
int nameCardID;
char personName[20];
char companyName[20];
} NameCard;
Hence, I tried to use relational operators to compare between the values of the ID and copy it in ascending order to another temporary array I named fakeHolder, before finally copying over to the actual array. However, I can't seem to understand why it is not in order after inputting my data as ID 9, 7, 5.
Here is my helper function:
int addNameCard(NameCard *nc, int *size){
int i = 0;
// Why is this a pointer?
NameCard fakeHolder[10];
char dummy[100];
char *p;
printf("addNameCard():\n");
if(*size == MAX){
printf("The name card holder is full");
// To quit the program
return 0;
}
// Keeps it to Fake Name Card Holder First
printf("Enter nameCardID:\n");
scanf("%d", &fakeHolder->nameCardID);
scanf("%c", &dummy);
printf("Enter personName:\n");
fgets(fakeHolder->personName, 20, stdin);
if(p = strchr(fakeHolder->personName, '\n')){
*p = '\0';
}
printf("Enter companyName:\n");
fgets(fakeHolder->companyName, 20, stdin);
if(p = strchr(fakeHolder->companyName, '\n')){
*p = '\0';
}
// Compare the ID value
for(int j = 0; j < *size; j += 1){
if(fakeHolder->nameCardID == (nc+j)->nameCardID){
printf("The nameCardID has already existed");
}
else if(fakeHolder->nameCardID < (nc+j)->nameCardID){
fakeHolder[(j+1)].nameCardID = (nc+j)->nameCardID;
strcpy(fakeHolder[(j+1)].personName,(nc+j)->personName);
strcpy(fakeHolder[(j+1)].companyName, (nc+j)->companyName);
}
}
*size += 1;
// Transfer to the Actual Name Card Holder
for(int k = 0; k < *size; k += 1){
(nc+k)->nameCardID = fakeHolder[k].nameCardID;
strcpy((nc+k)->personName, fakeHolder[k].personName);
strcpy((nc+k)->companyName, fakeHolder[k].companyName);
}
printf("The name card has been added successfully\n");
return 0;
}
Your current code has several problems, and you can rewrite it to be much more maintainable and easier to work with. For example,
i (in int i = 0;) is not being used
scanf("%c", &dummy); is there, I assume, to remove trailing \n - but a 100-char buffer for a single character to read is... surprising. See scanf() leaves the new line char in the buffer for lots of discussion on different approaches to "trailing stuff after integer".
splitting addNameCard into 2 functions, one to actually request a NameCard and another to insert it into the array, would divide up responsibilities better, and make your program easier to test. Avoid mixing input/output with program logic.
The question you ask can be solved via the standard library qsort function, as follows:
#include <stdlib.h>
typedef struct{
int nameCardID;
char personName[20];
char companyName[20];
} NameCard;
void show(NameCard *nc, int n) {
for (int i=0; i<n; i++, nc++) {
printf("%d,%s,%s\n",
nc->nameCardID, nc->personName, nc->companyName);
}
}
// comparison functions to qsort must return int and receive 2 const void * pointers
// they must then return 0 for equal, or <0 / >0 for lower/greater
int compareCardsById(const void *a, const void *b) {
return ((NameCard *)a)->nameCardID - ((NameCard *)b)->nameCardID;
}
int main() {
NameCard nc[10];
nc[0] = (NameCard){1, "bill", "foo"};
nc[1] = (NameCard){3, "joe", "bar"};
nc[2] = (NameCard){2, "ben", "qux"};
show(nc, 3);
// calling the libraries' sort on the array; see "man qsort" for details
qsort(nc, 3, sizeof(NameCard), compareCardsById);
show(nc, 3);
return 0;
}

How to find the minimum number of coins needed for a given target amount(different from existing ones)

This is a classic question, where a list of coin amounts are given in coins[], len = length of coins[] array, and we try to find minimum amount of coins needed to get the target.
The coins array is sorted in ascending order
NOTE: I am trying to optimize the efficiency. Obviously I can run a for loop through the coins array and add the target%coins[i] together, but this will be erroneous when I have for example coins[] = {1,3,4} and target = 6, the for loop method would give 3, which is 1,1,4, but the optimal solution is 2, which is 3,3.
I haven't learned matrices and multi-dimensional array yet, are there ways to do this problem without them? I wrote a function, but it seems to be running in an infinity loop.
int find_min(const int coins[], int len, int target) {
int i;
int min = target;
int curr;
for (i = 0; i < len; i++) {
if (target == 0) {
return 0;
}
if (coins[i] <= target) {
curr = 1 + find_min(coins, len, target - coins[i]);
if (curr < min) {
min = curr;
}
}
}
return min;
}
I can suggest you this reading,
https://www.geeksforgeeks.org/generate-a-combination-of-minimum-coins-that-results-to-a-given-value/
the only thing is that there is no C version of the code, but if really need it you can do the porting by yourself.
Since no one gives a good answer, and that I figured it out myself. I might as well post an answer.
I add an array called lp, which is initialized in main,
int lp[4096];
int i;
for (i = 0; i <= COINS_MAX_TARGET; i++) {
lp[i] = -1;
}
every index of lp is equal to -1.
int find_min(int tar, const int coins[], int len, int lp[])
{
// Base case
if (tar == 0) {
lp[0] = 0;
return 0;
}
if (lp[tar] != -1) {
return lp[tar];
}
// Initialize result
int result = COINS_MAX_TARGET;
// Try every coin that is smaller than tar
for (int i = 0; i < len; i++) {
if (coins[i] <= tar) {
int x = find_min(tar - coins[i], coins, len, lp);
if (x != COINS_MAX_TARGET)
result = ((result > (1 + x)) ? (1+x) : result);
}
}
lp[tar] = result;
return result;
}

Find if 2 strings are composed of same letters

I have a problem, this function should return 1 if secret is composed of same letters than letters_guessed.
It works fine, as long as letters_guessed has atleast 1 same letter which are in the secret. If there is same letter 2 times or more, it does not work. I know why, but I can not solve it because I can not remove same letters.
I can not remove same letters from letters_guessed array, because it is constant, and I can not change it to nonconstant.
Again ...
If:
secret = "cat"
letters_guessed = "txaoc"
return 1
**Right**
If:
secret = "dog"
letters_guessed = "gefxd"
return 0
**Right**
If:
secret = "car"
letters_guessed = "ccr"
return 1
**Wrong, How can I solve this?**
Sorry for my bad English and long explanation.
Here is my program:
int is_word_guessed(const char secret[], const char letters_guessed[])
{
int same = 0;
for(int i = 0; i < strlen(letters_guessed); i++)
{
for(int j = 0; j < strlen(secret); j++)
{
if(letters_guessed[i] == secret[j])
same++;
}
}
if (same == strlen(secret))
return 1;
else
return 0;
}
You can:
make a copy of your strings in order to flag already counted letters (since you tell you don't want to modify the strings, I suggest making a copy first in order to discard already counted letters);
get sorted versions of your strings and then compare them with a single loop; this solution would also provide a better complexity (you could get O(n log n) instead of your current O(n^2)).
One way to do this without modifying the strings is to count the occurrences of letters in the strings. When the guess has more occurrences of a letter than the secret, it's a miss. The case where a letter occurs in the guess that isn't in the secret is just a special case, because then the count of occurrences in the secret is zero.
In practice, you don't keep two separate counts: Add the letters of the guess to the count first, then remove the letters of the secret. As soon as one count drops below zero, it's a miss.
You can make use of the fact that there are only 256 different chars and keep the counts in an array. The index to the array is the letter's ASCII code. Be careful not to access the array at negative indices. C's char isn't guaranteed to be unsigned, so you could cast it or use an unsigned temporary variable or chose not to consider negative values.
Here's an implementation:
int contains(const char *guess, const char *secret)
{
int count[256] = {0}; // start with all-zero array
while (*guess) {
unsigned char c = *guess++;
count[c]++;
}
while (*secret) {
unsigned char c = *secret++;
if (count[c] == 0) return 0;
count[c]--;
}
return 1;
}
You can keep iteration in memory by maintaining an array of all 26 alphabets.
Assumptions:- All letters should be in lower case. Secret should not have repeated letters.
Logic:- Make array entry to 1 if we have considered that letter. 97 is ascii value of 'a'
// declare header file
#include "string.h"
int is_word_guessed(const char secret[], const char letters_guessed[])
{
int same = 0;
int alphabets[26];
// make all enteries 0
for (int k = 0; k <= 25; k++)
{
alphabets[k] = 0;
}
for (int i = 0; i < strlen(letters_guessed); i++)
{
for (int j = 0; j < strlen(secret); j++)
{
if (letters_guessed[i] == secret[j] && (alphabets[(char)letters_guessed[i] - 97] == 0))
{
same++;
alphabets[(char)letters_guessed[i] - 97] = 1;
}
}
}
if (same == strlen(secret))
return 1;
else
return 0;
}
It's easy.
In Haskell it would be:
all (`elem` letters_guessed) secret
in other words: All chars in secret must be in letters_guessed.
In C its (not tested):
// Iterate though string 'secret' until there is a char not
// part of 'letters_guessed'. If there is none, return 1
unsigned check(char *secret, char *letters_guessed) {
unsigned length_secret = length(secret);
unsigned length_guessed = length(letters_guessed);
for (int i = 0; i < length_secret; i++) {
if (!elem(secret[i], letters_guessed) {
return 0;
}
}
return 1;
}
// Check if char 'current' is part of 'string'
unsigned elem(char current, char *string) {
unsigned length = length(string);
unsigned found = 0;
for (int i = 0; i < length; i++) {
if (current == string[i]) {
return 1;
}
}
return 0;
}

Resources