This function works well aside from not accepting 0 because it considers it NULL
void addtolist(int list[], int item){
for(int a=0;a<5;a++){
if(list[a]==NULL){
list[a]=item;
break;
}
}
}
Is there any way I can make the array accept zeroes?
Additional info: -List- is a simple int array, accepting -item- inputs with scanf
No, there's no way to distinguish between list[a] == NULL and list[a] == 0. list is nothing more than a block of memory where every 4 bytes are considered be an integer.
The basic problem is you want to distinguish between elements which are empty and those which have a value. There's a few ways to handle this.
Use a special integer.
You could define all negative numbers as "empty". Or, if you need negative values, perhaps just one value. INT_MIN is a good choice.
But special values lead to bugs, and there's no type checking to save you, and you need to specially initialize each list. There are better ways.
Use integer pointers.
Instead of storing integers, store pointers to integers. Now NULL works.
int main() {
int **list = calloc(10, sizeof(int*));
int num = 42;
list[5] = #
for( size_t i = 0; i < 10; i++ ) {
int *entry = list[i];
if( entry == NULL ) {
continue;
}
printf("%d\n", *entry);
}
}
The downside if you're storing pointers, so you have to remember to copy lest you alter the original memory. Also now NULL can't be used as a sentry to indicate the end of the array.
Use a hash or tree
The real solution is to change your data structure to better match the job. An array is great if you have a complete, ordered list of things easily indexed with integers. If you have an incomplete list with gaps, a hash might be a better fit. Here's an example using GLib's hash table.
#include <stdio.h>
#include <glib.h>
// A little convenience function for inserting integers into a hash
// that normally wants pointers.
gboolean hash_table_insert_int(
GHashTable *table, int key, int value
) {
return g_hash_table_insert( table, GINT_TO_POINTER(key), GINT_TO_POINTER(value) );
}
int main() {
GHashTable *numbers = g_hash_table_new(g_direct_hash, g_direct_equal);
// Add 5 -> 42 and 9 -> 23
hash_table_insert_int( numbers, 5, 42 );
hash_table_insert_int( numbers, 9, 23 );
// Iterate through the entries in the table.
GHashTableIter iter;
gpointer key, value;
g_hash_table_iter_init(&iter, numbers);
while( g_hash_table_iter_next(&iter, &key, &value) ) {
printf("%d -> %d\n", (int)key, (int)value);
}
}
GLib's data structures take some getting used to because it's designed to be type generic, but it's worth it for the robust flexibility they bring. Now you have a data structure which you can explicitly insert and delete entries without messing with special values, it knows its memory boundaries, and is memory and performance efficient.
Related
I have structure with most frequent words in huge text file, the field pointer array to char are words, and field count are their frequencies. My question is how to sort them from the longest word length to lowest - to nicely display it to user? Code:
typedef struct pair {
char * a[20000];
int count[32000];
} Pair;
Example print:
printf("%d, %d, %d\n", bag.count[0], bag.count[1], bag.count[2]); // -> 8, 7, 3
printf("%s, %s, %s\n", bag.a[0], bag.a[1], bag.a[2]); // -> abbes, abbey, abhor
I'd suggest to turn the structure/array inside-out.
Having your arrays inside the struct does not feel right. Because you primarily have a pair of things, and secondarily you want one array of these things. Do you see what I mean?
It would look like this:
typedef struct pair
{
char* word;
int count;
} Pair;
Pair pairs[32000];
You'd also need to know how many pairs are filled. (You would have needed this anyway.):
int index; // Index of next free pair.
Then use C standard qsort():
#include <stdlib.h>
...
int comparePairs(const void *pairA, const void *pairB)
{
Pair* a = (Pair*)pairA;
Pair* b = (Pair*)pairB;
return strlen(a->word) - strlen(b->word);
}
qsort(pairs, index, sizeof(Pair), comparePairs);
The index would start at 0, which indicates the next free Pair is at that index. Adding an element would be:
pairs[index].word = someWord; // someWord must be allocated elsewhere!
pairs[index].count = 1;
index++;
Note that, because your structure only has a char pointer, that the someWord must be allocated elsewhere. Without automatic memory management this is going to be rather cumbersome. A better alternative would be to strcpy() the word in by using the following structure:
typedef struct pair
{
char word[50]; // Assumes a word is NEVER longer than 49 characters.
int count;
} Pair;
Adding a new element would then become:
strncpy(pairs[index].word, someWord, 50 - 1);
pairs[index].count = 1;
index++;
The strncpy() above copies at most 49 characters. You need to make sure you chose this 50 or whatever size wisely to make sure strncpy() never starts chopping off ends of your very long words.
But of course to know if you have to add a new or simply increment the count of an existing one, you'd first need to search through the existing Pairs with a simple loop.
I am learning C language. I want to know the size of an array inside a function. This function receive a pointer pointing to the first element to the array. I don't want to send the size value like a function parameter.
My code is:
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
while( *(a + i) != NULL )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
My code doesn't show any number. How can I fix it?
Thanks.
Arrays in C are simply ways to allocate contiguous memory locations and are not "objects" as you might find in other languages. Therefore, when you allocate an array (e.g. int numbers[5];) you're specifying how much physical memory you want to reserve for your array.
However, that doesn't tell you how many valid entries you have in the (conceptual) list for which the physical array is being used at any specific point in time.
Therefore, you're required to keep the actual length of the "list" as a separate variable (e.g. size_t numbers_cnt = 0;).
I don't want to send the size value like a function parameter.
Since you don't want to do this, one alternative is to use a struct and build an array type yourself. For example:
struct int_array_t {
int *data;
size_t length;
};
This way, you could use it in a way similar to:
struct int_array_t array;
array.data = // malloc for array data here...
array.length = 0;
// ...
some_function_call(array); // send the "object", not multiple arguments
Now you don't have to write: some_other_function(data, length);, which is what you originally wanted to avoid.
To work with it, you could simply do something like this:
void display_array(struct int_array_t array)
{
size_t i;
printf("[");
for(i = 0; i < array.length; ++i)
printf("%d, ", array.data[i]);
printf("]\n");
}
I think this is a better and more reliable alternative than another suggestion of trying to fill the array with sentinel values (e.g. -1), which would be more difficult to work with in non-trivial programs (e.g. understand, maintain, debug, etc) and, AFAIK, is not considered good practice either.
For example, your current array is an array of shorts, which would mean that the proposed sentinel value of -1 can no longer be considered a valid entry within this array. You'd also need to zero out everything in the memory block, just in case some of those sentinels were already present in the allocated memory.
Lastly, as you use it, it still wouldn't tell you what the actual length of your array is. If you don't track this in a separate variable, then you'll have to calculate the length at runtime by looping over all the data in your array until you come across a sentinel value (e.g. -1), which is going to impact performance.
In other words, to find the length, you'd have to do something like:
size_t len = 0;
while(arr[len++] != -1); // this is O(N)
printf("Length is %u\n", len);
The strlen function already suffers from this performance problem, having a time-complexity of O(N), because it has to process the entire string until it finds the NULL char to return the length.
Relying on sentinel values is also unsafe and has produced countless bugs and security vulnerabilities in C and C++ programs, to the point where even Microsoft recommends banning their use as a way to help prevent more security holes.
I think there's no need to create this kind of problem. Compare the above, with simply writing:
// this is O(1), does not rely on sentinels, and makes a program safer
printf("Length is %u\n", array.length);
As you add/remove elements into array.data you can simply write array.length++ or array.length-- to keep track of the actual amount of valid entries. All of these are constant-time operations.
You should also keep the maximum size of the array (what you used in malloc) around so that you can make sure that array.length never goes beyond said limit. Otherwise you'd get a segfault.
One way, is to use a terminator that is unique from any value in the array. For example, you want to pass an array of ints. You know that you never use the value -1. So you can use that as your terminator:
#define TERM (-1)
void print(int *arr)
{
for (; *arr != TERM; ++arr)
printf("%d\n", *arr);
}
But this approach is usually not used, because the sentinel could be a valid number. So normally, you will have to pass the length.
You can't use sizeof inside of the function, because as soon as you pass the array, it decays into a pointer to the first element. Thus, sizeof arr will be the size of a pointer on your machine.
#include <stdio.h>
void ShowArray(short* a);
int main (int argc, char* argv[])
{
short vec[] = { 0, 1, 2, 3, 4 };
short* p = &vec[0];
ShowArray(p);
return 0;
}
void ShowArray(short* a)
{
short i = 0;
short j;
j = sizeof(*a) / sizeof(short);
while( i < j )
{
printf("%hd ", *(a + i) );
++i;
}
printf("\n");
}
Not sure if this will work tho give it a try (I don't have a pc at the moment)
I need to create an array of integers with the aim of using them one by one later in the program. Integers are inputted by the user, so the size of the array and the size of each integer aren't constant. All I can say that due to specification of the program the array would not exceed, let's say, 100 elements and an integer would always be between 0 and 99. How can I do this? I am new to C and this is really baffling to me, as this is very easy to do in Python, and I've spent quite some time already trying to figure out how to make this work (I understand that all those complications with arrays arise from the fact that C is an old language).
First, don't confuse an integer value with the size of the type used to represent it. The values 0 and 99 will take up exactly the same amount of space in whatever integral type you use.
As for the array itself, you have several options available.
You can pick a meximum number of elements that your user won't be allowed to exceed:
#define MAX_ALLOWED 100
int main( void )
{
int values[MAX_ALLOWED]; // declare array with max-allowed values
size_t howMany;
// get howMany from user, make sure it doesn't exceed MAX_ALLOWED
...
}
If you are using a C99 or C2011 compiler that supports variable-length arrays, you could get the array length from the user and use that value in the array
declaration:
int main( void )
{
size_t howMany;
// get howMany from user
int values[howMany]; // declare array with user-specified number of values
...
}
If you don't want to use VLAs (and there are some good reasons why you don't), you can use dynamic memory management routines:
#include <stdlib.h>
int main( void )
{
size_t howMany;
// get howMany from user
int *values = malloc( howMany * sizeof *values ); // dynamically allocate
// space to store user-
// specified number of
// values.
if ( !values )
{
// memory allocation failed, panic
exit( 0 );
}
...
free( values ); // release the memory when you're done.
}
Note that in the last case, values is not declared as an array of int, but a pointer to int; it will store the address of the memory that was dynamically allocated. You can still use the [] operator to index into that space like a regular array, but in many other respects it will not be treated the same as an array.
Regardless of how you create the array, assigning elements is the same:
for ( size_t i = 0; i < howMany; i++ )
{
values[i] = value_for_this_element();
}
After about 5 years of programming in dynamic languages such as Python and JS I am starting to feel I'm missing out of what happens under the hood. Languages such as these are really great because they let you focus on what you have to do leveraging the trouble of working with pointers, memory allocation and many searching, sorting, inserting algorithms. Even though I never regret using these languages as I really feel they are ridiculously powerful I feel that, in order to become a better programmer, I need to take a step back and understand what happens under the hood!
I decided to do this by writing a simple word counter: The app gets all the params and outputs all the unique words, each one with a counter: "Hello world Hello" would return "Hello: 2", "world: 1" (not taking in consideration the actual output structure). This program is the Python equivalent of:
import sys
from collections import defaultdict
def main():
results = defaultdict(int)
for word in sys.argv[1:]:
results[word] += 1
print results
Writing it in C is a bit different, I feel like I'm getting something utterly wrong with pointers, arrays of pointers and all that stuff! I want to get better, Help me get better!!
#include <stdio.h>
#include <stdlib.h>
// This is what a key-value pair: <int, string>
typedef struct {
int counter;
unsigned char* word;
} hashmap;
// Checks if inside the array of results, hashmap->word is equals to word paramter
hashmap* get_word_from_results(hashmap* results[], int count, const char* word) {
int i;
hashmap* result;
for (i = 0; i < count; i++) {
result = results[i];
if (result->word == (unsigned char *)word)
return result;
}
return NULL;
}
int main(int argc, const char *argv[])
{
hashmap* results;
int results_counter = 0;
int i;
const char* word;
for (i = 1; i < argc; i++) {
word = argv[i];
hashmap* result = get_word_from_results(&results, results_counter, word);
// If result is NULL, means word is not inserted yet, let's create a new hashmap and insert it inside the array
if (result == NULL) {
hashmap h;
h.counter = 1;
h.word = (unsigned char *)word;
results = realloc(NULL, (results_counter + 1) * sizeof(hashmap) );
// NOTE: potential memory leak? would h be deallocated?
results[results_counter] = h;
results_counter++;
printf("NEW\n");
} else {
// The word already exists in the hashmap array, let's increase it by 1
result->counter++;
printf("INCREMENTED\n");
}
}
return 0;
}
Can anyone give me some advice? what am I doing wrong here? Are my pointers okay? also I think I spotted a memory leak (see comments), would anyone like to submit their version??
Thanks!! you guys are so cool!!
Daniel
The major pointer issue in your program is that when hashmap* results is passed to realloc for the first time, its value is uninitialized. This is undefined behavior. You should initialize the pointer to NULL, like this:
hashmap* results = NULL;
The other problem is comparing strings: you need to use strcmp rather than ==. Remember that strcmp returns zero when strings are equal.
There are also memory leaks at the end of your program. You should free results, along with the words that are stored inside its elements.
Of course the thing that you call hashmap behaves precisely like a dynamic array. Programming a hash table in C presents a different level of challenge, however, so I would encourage you to make your current approach work.
For an assignment at school, we have to use structs to make matrices that can store a infinite amount of points for an infinite amount of matrices. (theoretical infinite)
For the assignment I decided to use calloc and realloc. How the sizes for the matrix go is: It doubles in size every time its limit is hit for its points (so it starts at 1, then goes to 2, then 4 and so on). It also doubles in size every time a matrix is added as well.
This is where my issue lies. After the initial matrix is added, and it goes to add the second matrix name and points, it gives me the following:
B???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
B is the portion of it that I want (as I use strcmp later on), but the ? marks are not supposed to be there. (obviously)
I am not sure why it is exactly doing this. Since the code is modular it isn't very easy to get portions of it to show exactly how it is going about this.
Note: I can access the points of the matrix via its method of: MyMatrix[1].points[0].x_cord; (this is just an example)
Sample code that produces problem:
STRUCTS:
struct matrice {
char M_name[256];
int num_points[128];
int set_points[128];
int hasValues[1];
struct matrice_points * points;
} * MyMatrix;
struct matrice_points {
int set[1];
double cord_x;
double cord_y;
};
Setup Matrix Function:
void setupMatrix(){
MyMatrix = calloc(1, sizeof(*MyMatrix));
numMatrix = 1;
}
Grow Matrix Function:
void growMatrix(){
MyMatrix = realloc(MyMatrix, numMatrix * 2 * sizeof(*MyMatrix));
numMatrix = numMatrix * 2;
}
Add Matrix Function which outputs this problem after growing the matrix once.
void addMatrix(char Name, int Location){
int exists = 0;
int existsLocation = 0;
for (int i = 0; i < numMatrix; i++){
if (strcmp(MyMatrix[i].M_name, &Name) == 0){
exists = 1;
existsLocation = i;
}
}
*MyMatrix[Location].M_name = Name;
printf("Stored Name: %s\n", MyMatrix[Location].M_name);
*MyMatrix[Location].num_points = 1;
*MyMatrix[Location].set_points = 0;
*MyMatrix[Location].hasValues = 1;
MyMatrix[Location].points = calloc(1, sizeof(*MyMatrix[Location].points));
}
void addMatrix(char Name, int Location)
char Name represents a single char, i.e. a integer-type quantity. char is just a number, it's not a string at all.
When you do this:
strcmp(..., &Name)
you're assuming that the location where that one character is stored represents a valid C string. This is wrong, there is no reason why this should be the case. If you want to pass a C string to this function, you will need to declare it like this:
void addMatrix(char *Name, int Location)
Then you need to copy that C string into the appropriate place in your matrix structure. It should look like:
strncpy(... .M_name, Name, max_number_of_chars_you_can_store_in_M_Name);
Also these field definitions are strange in your struct:
int num_points[128];
int set_points[128];
int hasValues[1];
This means that your struct will contain an array of 128 ints called num_points, another array of 128 ints calls set_points, and an array of one int (strange) called hasValues. If you only need to store the count of total points and set points, and a flag indicating whether values are stored, the definition should be:
int num_points;
int set_points;
int hasValues;
and correct the assignments in your addMatrix function.
If you do need those arrays, then your assignments as they are are wrong also.
Please turn on all warnings in your compiler.
Try adding '\0' to the end of your data.
*MyMatrix[Location].M_name = Name;
You're copying a single character here, not a string. If you want a string, Name should be defined as char *, and you should be using strcpy.