Pointer and struct array manipulation in C - c

#define MAX_KEYS 65
struct Key {
int id;
char cryptkeys[MAX_KEYS];
};
int main(int argc, char ** argv) {
int MAX_LINE = 69;
struct Key *table[3];
struct Key *(*p)[] = &table;
//allocating space for the pointers in array
for(int i = 0; i < 4; i++) {
table[i] = malloc(sizeof(struct Key));
}
//parsing the id and the keys
char id[3];
char key[65];
for(int i = 0; i < size-1; i++) {
struct Key *k = (struct Key*)malloc(sizeof(struct Key));
string = a[i];
strncpy(id, string, 3);
id[3] = '\0';
k->id = atoi(id);
for(int j = 4; j < strlen(string); j++) {
key[j-4] = string[j];
}
strcpy(k->cryptkeys, key);
table[i] = k;
printf("%s", table[i]->cryptkeys); //this will print
}
for(int i = 0; i < sizeof(table) -1; i++) {
printf("%d", table[i]->id); //seg fault here, what is the difference from above?
printf(" ");
printf("%s", table[i]->cryptkeys);
}
return 0;
}
Hi everyone, I had a question about manipulating pointers in C. I have declared an array of pointers that will be filled with structs that I have created. Each struct accepts a int and string value that I read in from a file. My question is about editing the values inside of my array, specifically assigning new values and accessing the values already in there. I assign my values after parsing them from the file, but I get a segmentation fault when I try to print them out below. Why does my code keep segfault in my last loop, do I have to print out values in an array of pointers differently than I normally would? Thank you!

sizeof(table) is not 3. It's actually 24 which is 3*8 (number of array elements*size of an address). You get segmentation fault because you try to access table[3] (and so on) which is not allocated.

Related

Why do I get a segmentation fault by declaring a 2d array in c?

I am new to threads and I have a program that uses threads to find the minimum number out of a 2d array and later on, it finds the distance that the other elements of the array have from the minimum number and stores them in another array.
The user should enter the size of the array and the number of threads he wants to use.
I tried the program below for 1d array and it worked just fine. When I converted it to work for a 2d array it started crashing and throwing a segmentation fault. I, however, cannot find which part of the 2d declaration is wrong.
Any help is really appreciated.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <pthread.h>
struct Parameters
{
// input
int s,p; //n is size of array, p is number of threads
int** array; //array with elements
int start;
int end;
// output
int smallest;
int pos; //position if minimum
int** B; //array that holds the distances
};
void* min(void* args)
{
struct Parameters* p = (struct Parameters*)args;
int **array = p->array;
int **B1 = p->B;
int start = p->start;
int end = p->end;
int smallest = array[start][start];
int pos = p->pos;
int distance;
//find the smallest
for (int i = start; i < end; i++)
{
for(int j = start; j < end; j++)
{
if (array[i][j] < smallest)
{
smallest = array[i][j];
pos = i;
}
}
}
//find the distances
for(int i = 0; i < ((struct Parameters*)args) -> s; i++)
{
for(int j = 0; j < ((struct Parameters*)args) -> s; j++)
{
distance = abs(pos - i);
B1[i][j] = distance;
}
}
params->smallest = smallest;
params->B = B1;
return NULL;
}
int main()
{
int smallest,pos;
int s,p;
struct Parameters *ptr = (struct Parameters *)malloc(sizeof(struct Parameters));
if(ptr == NULL)
{
printf("Not enough. Try again \n");
exit(0);
}
printf("Type s\n");
scanf("%d",&(ptr->s));
printf("Type p\n");
scanf("%d", &(ptr->p));
// declare an array of threads and associated parameter instances
pthread_t threads[(ptr->p)];
struct Parameters thread_parameters[(ptr->p)] ;
int arr[ptr->s][ptr->s];
int B2[ptr->s][ptr->s];
// intialize the array
for(int i=0; i< ptr->s; i++)
{
for(int j=0; j< ptr->s; j++)
{
printf("Type a \n");
scanf("%d",&arr[i][j]);
}
}
// smallest needs to be set to something
smallest = arr[0][0];
// start all the threads
for (int i = 0; i < ptr->p; i++)
{
memcpy(arr, thread_parameters[i].array, sizeof(arr));
thread_parameters[i].s = ptr->s;
memcpy(Bb, thread_parameters[i].B, sizeof(B2));
thread_parameters[i].start = i * (ptr->s / ptr->p);
thread_parameters[i].end = (i+1) * (ptr->s / ptr->p);
pthread_create(&threads[i], NULL, min, &thread_parameters[i]);
}
// wait for all the threads to complete
for (int i = 0; i < ptr->p; i++)
{
pthread_join(threads[i], NULL);
}
// Now aggregate the "smallest" and "largest" results from all thread runs
for (int i = 0; i < ptr->p; i++)
{
if (thread_parameters[i].smallest < smallest)
{
smallest = thread_parameters[i].smallest;
}
}
printf("Smallest is %d\n", smallest);
thread_parameters[ptr->p].B[ptr->s][ptr->s];
for (int i = 0; i < 1; i++)
{
for(int j = 0; j < ptr->s;j++)
{
for(int k = 0; k < ptr->s; k++)
{
printf("Element %d is %d away from min\n",j,thread_parameters[i].B[j][k]);
}
}
}
return 0;
}
Thank you!!
The issue with your code might also come from :
memcpy(arr, thread_parameters[i].array, sizeof(arr));
...
memcpy(Bb, thread_parameters[i].B, sizeof(B2));
as thread_parameters[i].array and thread_parameters[i].B are not allocated, if you are only reading the array it might b fine to only pass them by address
thread_parameters[i].array = arr
but for thread_parameters[i].B you would need to allocate the arrays and perform a deep copy (memcpy would not work)
The below text does not answer the question but does provide some insight on VLA usage
One reason for causing the segmentation with a declaration of a Variable Length Array is that the value is to large to allocate the array on the stack (some compiler choose this option, this choice might have performance reason).
The is not much option to recover cleanly from failure to allocate memory on the stack as there is little way to clean up stack memory during runtime within the same stack context.
You can mitigate the issue by allocating your 2D arrays on the heap instead, some of the strategies are available here(thanks #Lundin) and here.
int** alloc_2d_int_array(size_t rows, size_t cols) {
int **result = malloc(rows * sizeof(int *));
if(result == NULL) {
// could not allocate more memory
return NULL;
}
size_t row_size = cols * sizeof(int);
for(int i=0; i < rows; ++i) {
result[i] = malloc(row_size);
if(result[i] == NULL) {
// could not allocate more memory
// cleanup
return NULL;
}
}
return result;
}
the above implementation have not been tested, but does compile, there are still risk of integer overflow.
Then use the above define function as following:
int **arr = alloc_2d_int_array(ptr->s, ptr->s);
int **B2 = alloc_2d_int_array(ptr->s, ptr->s);
easier implementation (see here(thanks #Lundin))
int **arr = malloc(sizeof(int[ptr->s][ptr->s]);
int **B2 = malloc(sizeof(int[ptr->s][ptr->s]);

parse 2d dynamic int array to Shared Memory

Im trying to build a program that parsing a 2d dynamic array to other program by using shared memory.I search a lot but im a bit confused because im not familiar at this one.
My code so far:
int main (int argc, char* argv []){
int rows,columns;
if( argc < 3 ){
printf("Need The size of the 2d array\n");
return 0;
}
rows = atoi(argv[1]);
columns = atoi(argv[2]);
time_t t;
srand((unsigned) time(&t));
key_t key = ftok(".",'a');
size_t size = sizeof(key_t) + (rows * columns + 2 + rows) * sizeof(int);
int shmid = shmget(key,size,IPC_CREAT|IPC_EXCL|S_IRWXU);
int *memory = shmat(shmid, NULL, 0);
printf("Shared Memory Key: %d\n", key);
int *argsflag = memory;
int *resflag= memory + 1;
int *res = memory + 2;
int **array = (int **) memory + (rows*columns);
for(int i = 0; i < rows ; i++) {
for(int j = 0; j < columns; j++) {
array[i][j] = rand() % 100;
}
}
for(int i = 0; i < rows ; i++) {
for(int j = 0; j < columns; j++) {
printf("%d ",array[i][j]);
}
printf("\n");
}
shmctl(shmid,IPC_RMID,NULL);
shmdt(memory);
return(0);
}
Im getting a Segmentation fault (core dumped) and i dont know why.Also by searching i find a solution with struct but i dint get how i can build that.
You cannot have a int** point at a 2D array. It can only point to the first element in a 1D array of int*.
Furthermore, what's the logic of memory + (rows*columns)? You end up setting the pointer to the last item of the array, rather than the first.
Try this instead:
void* memory = shmat( ...
...
int (*array)[columns] = memory;
...
array[i][j] = ... ;
Where int (*array)[columns] is an array pointer, which ends up point at the first array in the 2D array.
For details, see Correctly allocating multi-dimensional arrays.

Undefined behavior with 2d array of struct C

I have a 2d array of structs that I am assigning strings to, here is my struct.
struct node {
char* value;
};
Here is my allocation (I am new to C so I am not sure if it is right) but there will always be 35 columns but there could be millions of rows.( I just had it at 3 for now for testing)
const int rows=3;
struct node ** arrayofnodes[rows][35];
for(int i=0; i<rows; i++) {
array[i] = malloc(test * sizeof array[0]);
for(int j=0; j<35; j++) array[i][j] = malloc(sizeof array[0][0]);
}
I then read in character by character from a csv file and have a temp string, and assign the value of the temp to the position I want by using this below.
//int row and count are defined in my while loop I have for counting commas(or what col I am on) then new lines for the rows
arrayofnodes[row][count]->value=strdup(temp);
printf("%s \n", arrayofnodes[row][count]->value);
printf("%d %d \n",row, count );
When I assign like the way above it seems to work. I added these print statements in to make sure it was assigning the right values.
For example above would print out something like
Red
0 0
And this is correct for that position.
But then after I do all of my assigning. I placed a print statement printf("%s \n", arrayofnodes[0][0]->value); to test if I can retrieve the 1st value as shown above which should be "Red".
In my terminal it outputs "#`??" or "#Pz?" or just any random output. I have tried this for a bunch of different positions besides 0,0, but they all get the same outcome. I guess I am just confused why the print statements work right after I assign them, but not at the end of my code when I call them later.
This is what it looks like you're trying to do. You will need to scan your csv file and compute the number of rows required, then populate the values however you want.
#include <stdio.h>
#include <stdlib.h>
struct node {
char* value;
};
int main() {
const int rows = 3; // you will need to compute this beforehand
const int columns = 35;
struct node** arrayofnodes = malloc(rows * sizeof(struct node*));
for (int i = 0; i < rows; ++i) {
arrayofnodes[i] = malloc(columns * sizeof(struct node));
}
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
arrayofnodes[i][j].value = malloc(...);
strcpy(arrayofnodes[i][j].value, ...); // etc..
}
}
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < columns; ++j) {
free(arrayofnodes[i][j].value);
}
}
for (int i = 0; i < rows; ++i) {
free(arrayofnodes[i]);
}
free(arrayofnodes);
}
You can avoid overcomplicated allocation by using constant size inside the structure:
struct OneRow
{
char Value[35];
}
const int Rows=3;
OneRow *MyArray=NULL;
MyArray = (OneRow*) malloc (Rows*sizeof(OneRow));
You can now access each element (character) or a whole string as
MyArray[rownumber].Value[colnumber] = …
strcpy (MyArray[rownumber].Value, "I'm_shorter_than_35"); //34 chars max + null-term

Pass char** as an argument to a function in C

I know there are many topics of this kind but I've read several of them and still can't figure out what am I doing wrong.
I've successfully generated a char** array. My bubble sort function probably works as well. But when I passed the generated array to the function, only 1 row is copied.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>
void sort(char** tab)
{
char* temp;
int i, j, size = sizeof(tab)/sizeof(tab[0]);
printf("%d\n", size);
for(i = 0; i < size; ++i)
{
for(j = i+1; j < size; ++j)
{
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
}
}
for(i = 0; i < sizeof(tab)/sizeof(tab[0]); ++i)
puts(tab[i]);
}
int main()
{
srand(time(NULL));
int size = rand()%5+5, i, j, s;
char** tab = (char**)malloc(size * sizeof(char*));
for(i = 0; i < size; ++i)
{
s = rand()%9+1;
tab[i] = (char*)malloc(s+1);
for(j = 0; j < s; ++j)
tab[i][j] = 'a'+rand()%26;
tab[i][s] = 0;
}
for(i = 0; i < size; ++i)
puts(tab[i]);
puts("");
sort(tab);
return 0;
}
Here's how the code works.
And when I write size=5 before the loop in the function it returns segmentation fault.
Edit: Same with passing the size of the array as an argument:
http://ideone.com/3Wvncq
Final code
I've fixed all the problems and here's the final code.
I was misinterpreting segmentation fault as the result of assigning a fixed size instead of not allocating the temp variable.
Thank you for all the answers.
Don't calculate size inside function void sort(char** tab) . As in this function it will be calculated as -
int i, j, size = sizeof(tab)/sizeof(tab[0]); // equivalent to sizeof(char **)/sizeof(char*) in function giving wrong length as you desire.
It's length in main(size is generated using rand so no need to find it) and then pass it as argument to function sort.
Declare your function like this -
void sort(char** tab,size_t size)
And while calling from main pass length of tab to it -
sort(tab,size); // size will be number of elements in tab calculated in main
You get segmentation fault because of this -
if(strcmp(tab[j-1], tab[j]) > 0)
strcpy(temp, tab[j-1]),
strcpy(tab[j-1], tab[j]),
strcpy(tab[j], temp);
temp is uninitialized in sort and still you pass it to strcpy thus undefined behaviour . Initialize temp before passing to strcpy.Allocate memory to temp in function sort.
In your sort function you declare the temp variable:
char* temp;
Later you use it as destination (and source) for string copying:
strcpy(temp, tab[j-1]),
But nowhere in between do you make temp point anywhere, temp is uninitialized and that leads to undefined behavior and your crash.
Don't use a pointer, instead declare it as an array of the largest string size possible.

whats going wrong with my program?

the program is supposed to compare the strings and place them in alphabetical order, but the final printf statement prints garbage...where am i going wrong here?
i have used an array of pointers to strings and declared them in the begining, i have even tried using temp as an array rather than pointer stil doesnt quite work
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int j;
int i;
char *temp;
char *string[5] = {"ibrahim","laura","peter","degea"};
for ( i = 0; i< 4;i++)
printf("%s\n", string[i]); //allocating memory
for( i = 0; i< 10 ;i++)
string[i] = (char*)malloc (30 * sizeof(char));
temp = (char*)malloc(30*sizeof(char));
for ( i=0; i< 3; i++)
for(j =i+1; j<4; j++)
{
if(strcmp(string[i], string[j]) > 0)
{
strcpy(temp, string[i]);
strcpy(string[i], string[j]);
strcpy(string[j], temp);
}
}
for (i = 0; i< 4; i++)
{
printf("%s\n",string[i]);
puts("\n");
}
free(string);
free(temp);
return 0;
}
string[i] = (char*)malloc (30 * sizeof(char));
This is overwriting the existing initialized values.
EDIT
for( i = 0; i< 10 ;i++)
temp = (char*)malloc(30*sizeof(char));
WHAT? you are allocating memory over and over 10 times on a single pointer?
EDIT 2:
The original post is lost (read Edited). By the time you are reading this answer, both Mr. Jonathan Leffler and this poster migh look like absolute fools in this world.
The code originally destroyed its data array (by allocating new pointers). Now it seems to throw memory away by allocating temp four times (but Jeevan's edit reinstates the old code in indented form). The old code allocated space for strings but never initialized them (having thrown away the value that was in the array beforehand).
NB: any commentary on the code could easily be invalid by the time you're reading the commentary — the code in the question could have changed.
for (i = 0; i < 10; i++)
string[i] = malloc(30);
This code tramples out of the bounds of the string array (dimension is 5). It also loses the data originally in the array.
You need to use strcmp() to compare the strings, but you simply need to swap pointers rather than using strcpy() at all.
The comment // allocating memory beside a printf() statement is misleading, too.
This stands a chance of working. Note that there is no memory allocation:
#include <stdio.h>
#include <string.h>
int main(void)
{
int j;
int i;
char *string[] = { "ibrahim", "laura", "peter", "degea" };
for (i = 0; i < 4; i++)
printf("%s\n", string[i]);
for (i = 0; i < 3; i++)
{
for (j = i+1; j < 4; j++)
{
if (strcmp(string[i], string[j]) > 0)
{
char *temp = string[i];
string[i] = string[j];
string[j] = temp;
}
}
}
for (i = 0; i < 4; i++)
printf("%s\n",string[i]);
return 0;
}
Output:
ibrahim
laura
peter
degea
degea
ibrahim
laura
peter
Comment: don't try sorting thousands of strings using this sort algorithm.
You are overwriting the existing string array contents with malloc, that too 10 times.
Please use braces in your code for better understanding
for( i = 0; i< 10 ;i++)
string[i] = (char*)malloc (30 * sizeof(char));
temp = (char*)malloc(30*sizeof(char));
can be written as
for( i = 0; i< 10 ;i++) // why to allocate memory ten times, that too overwriting
{
string[i] = (char*)malloc (30 * sizeof(char));
}
temp = (char*)malloc(30*sizeof(char));
when you declare :
char *string[5] = {
"ibrahim",
"laura",
"peter",
"degea" };
the pointer *string[0] to *string[3] allocated to a address in the memory, where will stored the init values "ibrahim","laura"...
when you use malloc function for the pointer string[i] = (char*)malloc (30 * sizeof(char));
the pointer *string[0] to *string[4] will be allocated to another address in the memory. so the value at these address are different from that you initialized (ibrahim,laura).
you should use static array instead dynamic as below
char temp;
char string[5] = {
"ibrahim",
"laura",
"peter",
"degea" };
remove all the malloc, free function.

Resources