Making a linked list from command line arguments - c

I have to make a linked list from arguments entered from the command line. You are supposed to enter integers and make a linked list out of them. When you enter -1, then stop reading from the command line. Fairly simple, but I am having some trouble. What I have is:
#include <stdlib.h>
struct node
{
int grade;
struct node *next;
};
int
main (int argc, char *argv[])
{
struct node *root;
root = (struct node *) malloc (sizeof (struct node));
root->next = 0;
root->grade = 0;
int i;
for (i = 0; i < argc; i++)
{
if (&argv[i] == -1)
{
break;
}
else
{
struct node *new_item_ptr;
new_item_ptr = malloc (sizeof (struct node));
new_item_ptr->grade = (*int) argv[i];
(*new_item_ptr).next = root;
root = new_item_ptr;
}
}
}
I think I'm pretty close, but there are a few things that doesn't work correctly. For example, I don't think for(i = 0; i < argc; i++) is correct. And the compiler says that new_item_ptr->grade = (*int) argv[i]; is wrong also. Can anyone help me out with this? I think I'm close just have a few minor errors.

To begin with, you have malloc'ed a structure which is totally unnecessary. If the user enters no data, you can return an empty list indicated by root = NULL. So, the initial part could be:
root = ( struct node * ) NULL;
if ( argc < 2 )
return ( 0 );
As your code stands, the first node will always have 0 for root->grade. In the loop, you should allocate the memory and convert the argv[i] to integer using atoi. Finally, your loop should start with i=1 because argv[0] is the command name itself.

The various argv[i]s are C-strings (char*) not integers. You need to convert them to integers, and the best way to do that is with the atoi function:
int value = atoi(argv[i]);
if (value == -1) {
break;
} else {
// etc.
}
The function name atoi is supposed to be a mnemonic for "ASCII to integer." The syntax you're using to assign the next field of new_item_ptr is a little more complicated than it needs to be as well. You can use the arrow syntax to assign the next field just as you did to assign the grade field. This part should look like:
new_item_ptr->grade = atoi(argv[i]);
new_item_ptr->next = root;
Or, better still, re-use the value variable created at the top of this iteration of the for loop instead of running atoi again:
new_item_ptr->grade = value;
new_item_ptr->next = root;

Related

Segmentation fault causes previous function to not occur

Working on a project where I'm creating a linked list from items in a 2d array. The array has been populated correctly, but my method for creating the linked list is causing a segmentation fault. While trying to debug where the fault was occurring, I put a print statement one line above the method call, but the print statement never printed. But, if i commented out the method call, the print statement did print.
main()
{
struct String *list;
char words1[100][1000];
for(int i = 0; i < 100; i++)
words1[i][0] = '\0';
char *words2[100];
for(int i = 0; i < 100; i++)
words2[i] = words1[i];
char ** words = words2;
getStrings(words);
for(int i = 0; i < 100; i++)
{
if(words[i][0] == '\0') break;
printf("%s\n", words[i]);
}
printf("Creating list\n"); //**(RIGHT HERE)** <-----------
//createList(list, words);
//sortStrings(list);
showStrings(list);
return 0;
}
struct String
{
char *s;
struct String *next;
};
void createList(struct String * list, char **words)
{
list = NULL;
struct String *node;
int counter = 0;
while (1)
{
if (words[counter][0] == '\0') break;
printf("Adding: %s", words[counter]);
node = (struct String *) malloc(sizeof(struct String));
node->s = words[counter];
node->next = NULL;
list->next = node;
list = node;
counter++;
}
}
void getStrings(char **s)
{
int count = 0;
for(int i = 0; i < 1000; i++)
{
int ret = scanf("%[^;]", s[i]);
if(ret < 0) break;
count++;
getchar();
}
}
Why would a segmentation fault in the createList() method cause a function that should have been called before it to not execute (or at least not show up)?
Edit: Added getStrings() method to code.
printf function does not write data to standard output immediately, as it might be too slow to do. Instead it might collect data in an internal buffer of stdout object. Once buffer gets full (or sometimes when newline is reached) its content gets "flushed" (written to the underlying file). During normal execution this data is also written before program exits, but because your program gets terminated beforehand, it is not able to empty that buffer, losing data.
You can add fflush(stdout); statement after printf to force data to be written.
Normally when writing to terminal buffer is flushed at \n. I suspect you are writing to a pipe instead (might be your IDE redirects your program output).
You can read more abut file streams here: http://en.cppreference.com/w/cpp/io/c
And about fflush here: http://en.cppreference.com/w/cpp/io/c/fflush
You can also use setvbuf function to manipulate file object buffering: http://en.cppreference.com/w/cpp/io/c/setvbuf
main()
{
/* uninitialized list head must be initialized as NULL */
struct String *list = NULL;
. . .
void createList(struct String * list, char **words)
{
/* Value of list changing only in local scope, list must be a
`struct String **` type. */
list = NULL;
. . .
/* access to field on NULL pointer -> segmentation fault */
list->next = node;

Can someone help me find the segfault here?

EDIT: So, it turns out that 'index' was not being returned to 0. Well then. That fixed one segfault. But still getting a different segfault. Working on it.
node* new_node(void){
node* ptr = malloc(sizeof(node));
for (int i = 0; i<27; i++) {
ptr->next[i] = NULL;
}
return ptr;
}
bool load(const char* dictionary)
{
FILE* dict = fopen(dictionary, "r");
node* ptr = new_node;
char word[LENGTH+1];
int index = 0;
for (int c = fgetc(dict); c!=EOF; c = fgetc(dict)){
if(c!='\n'){
word[index]=c;
index++;
}
else {
for(int x=0; x<=index; x++){
int ch = (word[x] == '\'') ? 26 : tolower(word[x])-'a';
if (ptr->next[ch] == NULL){
ptr->next[ch] = new_node;
}
ptr = ptr->next[ch];
}
ptr->end=true;
}
}
return true;
}
I'm trying to implement a trie data structure for a dictionary but my program seems to segfault somewhere in this function. I can't seem to pin it down even with the help of GDB, so can someone give me a hand?
Node is defined as such:
typedef struct node{
bool end;
struct node* next[27];
} node;
Dictionary file:
a
aaa
aaas
aachen
aalborg
aalesund
aardvark
aardvark's
aardvarks
aardwolf
(...)
You have many issues in your code:
When you allocate memory with malloc, it is uninitialised. initialise it directly after allocating it, so that NULL pointers really are null. (calloc, a cousin of ´malloc´, initialises all memory to zero.)
When you loop over the word, you should nor include index:
for (int x = 0; x < index; x++) ...
When you have found the end of a word, you must reset the index to 0. Otherwise, you will append to the old word and overflow the buffer. (You should probably also enforce the upper bound of ´index´.)
Likewise, when you insert a word into the trie, you must reset your pointer for trie traversal to the trie's root. You need two pointers here: A root node pointer and an auxiliary pointer for traversing the trie.
As is, your trie is local to your function. Return the root node, so that other functions can use the trie, or NULL on failure.
Fix these, and you will have a non-crashing function. (It still leaks memory and may not construct the trie properly.)
node *load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
node *head = calloc(1, sizeof(node));
char word[LENGTH + 1];
int index = 0;
for (int c = fgetc(dict); c != EOF; c = fgetc(dict)) {
if (c != '\n') {
word[index] = c;
index++;
} else {
node *ptr = head;
for (int x = 0; x < index; x++) {
int ch = (word[x] == '\'') ? 26 : tolower(word[x]) - 'a';
if (ptr->next[ch] == NULL) {
ptr->next[ch] = calloc(1, sizeof(node));
}
ptr = ptr->next[ch];
}
ptr->end = true;
index = 0;
}
}
return head;
}
The line:
node* ptr = new_node;
and
ptr->next[ch] = new_node;
are not calling the function, but assigning the address of the function to ptr. Call the function instead.
This problem could have been prevented if compiler warnings: -Wall and -Wextra were enabled.
There is no bounds checking done on the array word. Use the value LENGTH to check if the index is in bounds before using it.
It isn't clear what the if statement inside the for loop is doing. It appears that every time a newline is found the whole array word is added to the tree, but the index isn't reset so the same array is added multiple times. At some point index will point out of bounds causing undefined behavior. You should reset index after you use the array word.
You forgot to reset index to 0 at the beginning of the loop.
You should also use calloc(1, sizeof(node)) instead of malloc(sizeof(node)) to avoid leaving memory uninitialized. I suggest you use valgrind to help you track problems of this kind in your code.
You should filter punctuation\unsupported characters a bit more. Any character outside of [a-z|A-Z|\n|\\] will crash your program because of
int ch = (word[x] == '\'') ? 26 : tolower(word[x])-'a';
if (ptr->next[ch] == NULL){
Given that you open a file, there might be a space somewhere or some unexpected character. You need something like
if(c!='\n'){
int num = (c == '\'') ? 26 : tolower(c)-'a');
if(num >=0 && num < 27)
{
word[index]=c;
index++;
}
}

C: Help understanding pointers

I have been building this hash table function that is given an array it gets a word from and a pointer to an array that it fills with my linked list struct. It compiles correctly but I get a segmentation fault at - *hashTable[hashVal] = *newNode; .
void hashTableCreate(char *array, list *hashTable[]) {
while(arrayPos < getArrayLength(array)) {
char *temp = getWord(array);
int hashVal = hashingFunc(temp);
if((*hashTable[hashVal]).word == temp ) {
(*hashTable[hashVal]).count = (*hashTable[hashVal]).count+1;
}
else {
list *newNode = malloc(sizeof(list));
strcpy(newNode->word,temp);
newNode->count = 1;
*hashTable[hashVal] = *newNode;
}
}
}
It's called like this:
void timeStructures(char *newArray) {
list *hashTable[3000];
hashTableCreate(newArray, hashTable);
}
I know this is to do with the way I am using my pointers but I can't figure it out. Any help would be appreciated.
There are several problems on this code:
You seem you are using extra asterisks when assigning newNode to hashTable.
You can use ++ operator to increment count, and use -> to access a member of a pointer to struct.
getWord is unknown to me, but seems impossible it can return a pointer to a string contained inside an element of hashTable, which means the next if will always be false (newNode's word is a copied string, not a pointer to array's word), as it compares memory addresses instead of strings.
You never free temp neither hashTable elements, which seems another misconception of what you are doing here.
As noted by #kaylum , you should initialize hashTable so you avoid comparing against unassigned array elements, neither modifying count on them.
hashTable has to be passed as a pointer to hashTableCreate, or this will work on a copied version of it:
Try this:
void hashTableCreate(char *array, list *(*hashTable[])) {
while(arrayPos < getArrayLength(array)) {
char *temp = getWord(array);
int hashVal = hashingFunc(temp);
if((*hashTable)[hashVal] != NULL &&
strcmp((*hashTable)[hashVal]->word, temp) == 0 ) {
(*hashTable)[hashVal]->count++;
}
else {
list *newNode = malloc(sizeof(list));
strcpy(newNode->word,temp);
newNode->count = 1;
(*hashTable)[hashVal] = newNode;
}
free(temp);
}
}
void timeStructures(char *newArray) {
list *hashTable[3000];
int i;
// Initialize hashTable pointers to NULL
for(i = 0; i < 3000; i++) {
hashTable[i] = NULL;
}
hashTableCreate(newArray, &hashTable);
// Free hashTable elements, malloc'ed at hashTableCreate
for(i = 0; i < 3000; i++) {
if(hashTable[i] != NULL) {
free(hashTable[i]);
}
}
}
Note 1: you never check if hashVal is higher than 3000, which might be fine if you know what you are doing, aka, you know hashingFunc will never return 3000 or higher. If you do not, you'll need to care about growing hashTable appropriately.
Note 2: executing getArrayLength on each loop might be a performance problem for large lists. You probably prefer to create a variable to contain its value and execute it only once.
Note 3: It might be some easier if you declare hashTable as a plain list of elements, not a list of pointers to elements, like list hashTable[3000];, but I don't know exactly what you're looking for. Also, it will always waste 3000 list elements of memory, so might be a performance problem.

How to set all values to NULL struct array within a struct array in C

Basically I have two structs and I want to make an array of A structs, and within each A struct I want an array of 50 B structs. So I assume that we will use double pointers.
struct A{
char* a_word;
struct B** b_list;
};
struct B{
char* b_word;
int b_value;
};
When call initialize function I initialize the structs like this. My goal is to set all the values to NULL when I allocate memory.
struct Word** initialize()
{
int k;
int i;
struct A** A_list = calloc(BUFFSIZE, sizeof(struct A*));
for(k =0; k < BUFFSIZE; k++)
{
A_list[k] = calloc (1, sizeof(struct A));
A_list[k]-> b_list = calloc(50, sizeof(struct B*));
for(i = 0; i < 50; i++)
{
A_list[k]->b_list[i] = calloc(1, sizeof(struct B));
}
}
return hashTable;
}
after initializing all these values I am able to do. . .
if(A[43]->a_word == NULL) //43 unallocated value
{
printf("This is null\n");
//program prints this statement - good
//program knows that this value is NULL
}
But I also want . .
if(A_list[44]->b_list[0] == NULL)
{
printf("This is also null");
//This should be printed but nothing happens
}
For some reason not matter if I set the above if statement to == NULL or != NULL the program outputs absolutely nothing from that if statement. What is going on in memory and how can I allocate everything correctly, and so the value is set to NULL as a default and so I can input a value?
EDIT: Also whenever try to do A_list[value1]->b_list[value2] = strdup("string"); I get a segmentation error, this most likely stems from the same problem.
As mentioned already by WhozCraig in a comment to the question, this code
for(i = 0; i < 50; i++)
{
A_list[k]->b_list[i] = calloc(1, sizeof(struct B));
initialises the first 50 elements of b_list to point to valid memory, that is to be non 0, assuming calloc() never fails. Being that optimistic you better test for those elements being != NULL.
... if I set the above if statement to == NULL or != NULL the program outputs absolutely nothing
The code does not seem to flush stdout here:
if(A_list[44]->b_list[0] == NULL)
{
printf("This is also null");
Change this by adding a final \n:
if(A_list[44]->b_list[0] != NULL)
{
printf("This isn't null\n");
As stdout is line buffered by default, all content will be flushed if a new-line is detected.

Pointer becomes null

I'm passing a file pointer to a function(A) which then opens the file, reads a line in a while loop (for each line in the file) and calls another function(B) using theses values. The issue is after running through function B once, the file pointer becomes NULL and I'm not sure why.
void readMatrixData(matrix *matrix, FILE *fileInput)
{
char buffer[30];
while(fgets(buffer, 30, fileInput) != NULL) {
char *splitString = strtok(buffer, ",");
int row = atoi(splitString);
splitString = strtok(NULL, ",");
int column = atoi(splitString);
splitString = strtok(NULL, ",");
int value = atoi(splitString);
insertNewNode(&matrix->rowArray[row], &matrix->columnArray[column], value, row, column);
}
}
I check if fopen returns NULL before calling function A, and it's not. I've also set a breakpoint on the while loop and the first time it hits, fileInput has some memory allocated. However, on the second loop fileInput becomes NULL and I'm not sure why.
EDIT:
Here's the insertNewNode function:
void insertNewNode(node **rowHead, node **columnHead, int value, int row, int column) {
//Get to the correct position in the column linked list
if (*columnHead == NULL) {
*columnHead = malloc(sizeof(node));
} else {
while((*columnHead)->nextColumn != NULL && (*columnHead)->nextColumn->row < row)
*columnHead = (*columnHead)->nextColumn;
}
//Get to the correct position in the row linked list.
if (*rowHead == NULL) {
*rowHead = malloc(sizeof(node));
} else {
while((*rowHead)->nextRow != NULL && ((*rowHead)->nextRow->column < column))
*rowHead = (*rowHead)->nextRow;
}
node *newNode = malloc(sizeof(node));
newNode->column = column;
newNode->row = row;
newNode->value = value;
(*columnHead)->nextColumn = newNode;
(*rowHead)->nextRow = newNode;
}
The structs involved are:
typedef struct matrix {
node **rowArray;
node **columnArray;
Size matrixDimensions;
} matrix;
typedef struct node {
int value;
int row;
int column;
struct node *nextColumn;
struct node *nextRow;
} node;
and I initialise the matrix arrays with:
node *columns[m->matrixDimensions.columns];
node *rows[m->matrixDimensions.rows];
for (int i=0; i< m->matrixDimensions.columns; i++)
{
columns[i] = NULL;
}
for (int i=0; i < m->matrixDimensions.rows; i++)
{
rows[i] = NULL;
}
m->columnArray = columns;
m->rowArray = rows;
Probably the function insertNewNode overwrites memory
Prefer strtol over atoi.
As #DavideBerra suggested, comment out the call to insertNewNode and step through the code to confirm you can make multiple iterations of your while loop.
I don't understand how you are initialising your matrix arrays using m->matrixDimensions.columns and m->matrixDimensions.rows. Are you using C99 VLAs?
Crank up the warning levels of your compiler and ensure zero-warning compilation.
You do not initialize the nextRow and nextColumn fields of your newly allocated node. Doing so should prevent you from at least some trouble. It is strange that you do not get a Segfault.
You are also mixing array and linked list, what could happen if you get "overflowing" values from your file ? I feel like the segfault is not far away from here. Be very careful, your code shows weird concept mixing !
As others had suggested you, comment your insertNewNode call and see if your loop is well performed. If it is, run your program step by step using a debugger. Hope this helps, good luck !
check the value of row and column before accessing matrix->rowArray and matrix->columnArray whether these values are less than the array size.
My guess is that the values row,column may be outside your matrix and thus overwriting memory. Add a check of the values you receive and make sure your matrix is large enough. Remember arrays are zero indexed in C.

Resources