C segmentation fault - c

I'm trying to create a sub array with the following function :
Track * subArray(Track * arr, int start, int end){
int size = end - start;
Track * t = malloc(sizeof(Track) * size);
for(int i = 0; i < size && start <= end; i++){
t[i] = arr[start++];
}
}
The size of the t pointer is always 8, even when I don't multiply it with size and I get a segmentation fault. I'm new to C so I don't know what is causing this exception.

This is why C is hard. It's an off by one error: You need to allocate (end-start+1) items and use <= in the loop. Try rewriting to something like this:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Track {
char* color;
} Track;
Track * subArray(Track* arr, int start, int end){
assert(end > start);
const int size = 1 + end - start;
printf("Allocating %d items\n", size);
Track* t = malloc(sizeof(Track)*size);
for(int i=start; i <= end; ++i) {
printf("at %d fetching %d\n", i-start, i);
t[i-start] = arr[i];
}
return t;
}
int main() {
Track *track = malloc(sizeof(Track) * 7);
track[0].color = "red";
track[1].color = "orange";
track[2].color = "yellow";
track[3].color = "blue";
track[4].color = "indigo";
track[5].color = "green";
track[6].color = "violet";
Track *sub = subArray(track, 3, 5);
printf("%s\n", sub[0].color);
printf("%s\n", sub[1].color);
printf("%s\n", sub[2].color);
}
Compiling and running:
$ cc -g -W -Wall a.c && ./a.out
Allocating 3 items
at 0 fetching 3
at 1 fetching 4
at 2 fetching 5
blue
indigo
green
Note that I'm copying the value of char* pointers here. That may lead to additional confusing stuff, just in case you think about copying my code (I just drafted something that works to illustrate the problem).
Update
You're using inclusive indices. In C, however, it's quite common to specify a start index and a length. A lot of standard library functions do this, and this is what you'll most likely see in production code. One reason may be that it's easier to reason with. In your case, the code would be
Track* subArray(Track* arr, const size_t start, const size_t length) {
Track* t = malloc(sizeof(Track) * length);
for (size_t i = 0; i < length; ++i)
t[i] = arr[i + start];
return t;
}
and the corresponding call would be
Track *sub = subArray(track, 3, 3);
In my eyes, this not only looks better; it's simpler and easier to understand.
Another thing that's common is to copy pointers instead of the whole structs. This will depend on how your code and data structures are organized. In that case, it's quite common to use a sentry value at the end of an array of pointers to mark its end: This will typically be a NULL pointer.
Keep practising and keep reading other people's code, and you'll soon discover C idioms and programming styles that will make your life much easier!

I think your error is that you're using <= in your tests when they should be <. This will prevent you from running off the end of your arrays.

Related

decreasing time it takes to run my program in c

I was writing a program that is reading from a file and then storing the data in two tables that are in a table of structure. I am expanding the tables with realloc and the time my program takes to run is ~ 0.7 s.
Can i somehow decrease this time?
typedef struct {
int *node;
int l;
int *waga;
} przejscie_t;
void czytaj(przejscie_t **graf, int vp, int vk, int waga) {
(*graf)[vp].node[(*graf)[vp].l - 1] = vk;
(*graf)[vp].waga[(*graf)[vp].l - 1] = waga;
(*graf)[vp].l++;
}
void wypisz(przejscie_t *graf, int i) {
printf("i=%d l=%d ", i, graf[i].l);
for (int j = 0; j < (graf[i].l - 1); j++) {
printf("vk=%d waga=%d ", graf[i].node[j], graf[i].waga[j]);
}
printf("\n");
}
void init(przejscie_t **graf, int vp, int n) {
*graf = realloc(*graf, (vp + 1) * sizeof(przejscie_t));
if (n == vp || n == -1){
(*graf)[vp].l = 1;
(*graf)[vp].node = malloc((*graf)[vp].l * sizeof(int));
(*graf)[vp].waga = malloc((*graf)[vp].l * sizeof(int));
}
else {
for (int i = n; i <= vp; i++) {
(*graf)[i].l = 1;
(*graf)[i].node = malloc((*graf)[i].l * sizeof(int));
(*graf)[i].waga = malloc((*graf)[i].l * sizeof(int));
}
}
}
Here some suggestions:
I think you should pre-calculate the required size of your *graf memory instead of reallocating it again and again. By using a prealloc_graf function for example.
You will get some great time improvement since reallocating is time-consuming especially when it must actually move the memory.
You should do this method especially if you are working with big files.
And since you're working with files, pre-calculating should be done easily.
If your files size are both light and heavy, you have two choices:
Accept your fate and allow your code to be a little bit less optimized on small files.
Create two init functions: The first one is optimized for small files, the other one will be for bigger files but... You will have to run some benchmarks to actually determine what algorithm is the best for each case before being able to implement it. You could actually automate that if you have the time and the will to do so.
It is important to check for successful memory allocation before trying to use the said memory because allocation function can fail.
Finally, some changes for the init function :
void init(przejscie_t **graf, int vp, int n) {
*graf = realloc(*graf, (vp + 1) * sizeof(przejscie_t));
// The `if` statement was redundant.
// Added a ternary operator for ``n == -1``.
// Alternatively, you could use ``n = (n == -1 ? vp : n)`` right before the loop.
for (int i = (n == -1 ? vp : n); i <= vp; i++) {
(*graf)[i].l = 1;
// (*graf)[X].l is is always 1.
// There is no reason to use (*graf)[X].l * sizeof(int) for malloc.
(*graf)[i].node = malloc(sizeof(int));
(*graf)[i].waga = malloc(sizeof(int));
}
}
I've commented everything that I've changed but here is a summary :
The if statement was redundant.
The for loop cover all cases with ternary operator for n
equals -1.
The code should be easier to understand and to comprehend this way.
The node and waga arrays were not being initialized "properly".
Since l is always equals 1 there was no need for an
additional operation.
This doesn't really change execution time tho since its constant.
I would also suggest that your "functions running allocation functions" should return a boolean saying if the function succeeded. In the case the allocation failed you can return false to say that your function failed.

Remove some elements from array and re-size array in C

Regards
I want to remove some elements from my array and re-size it.
for example my array is:
char get_res[6] = {0x32,0x32,0x34,0x16,0x00,0x00};
Now I want to remove elements after 0x16, so my desire array is:
get_res[] = {0x32,0x32,0x34,0x16};
what is solution?
You cannot resize arrays in C (unlike Python, for example). For real resizing, at least from an API user's point of view, use malloc, calloc, realloc, and free (realloc specifically).
Anyway, "resizing" an array can be imitated using
a delimiter; for example, a delimiter like 0xff could mark the end of the valid data in the array
Example:
#define DELIMITER 0xff
print_data(char* data) {
for (size_t i = 0; data[i] != DELIMITER; ++i)
printf("%x", data[i]);
}
a member counter; count the number of valid data from the beginning of the array onward
Example:
size_t counter = 5;
print_data(char* data) {
for (size_t i = 0; i < counter; ++i)
printf("%x", data[i]);
}
Notes:
Use unsigned char for binary data. char may be aliasing signed char, which you might run into problems with because signed char contains a sign bit.
There is no need to "remove" them. Just don't access them. Pretend like they don't exist. Same like in stacks, when you "pop" a value from the top of the stack, you just decrement the stack pointer.
Manipulating arrays in C isn't easy as it is for vector in C++ or List in Java. There is no "remove element" in C. I mean that you have to do the job yourself, that is, create another array, copy only the elements you want to this new array, and free the memory occupied by the previous one.
Can you do that? Do you want the code?
EDIT:
Try that. It's just a simple program that simulates the situation. Now, you have to see the example and adapt it to your code.
#include <stdio.h>
#include <stdlib.h>
int main() {
char get_res[6] = {0x32,0x32,0x34,0x16,0x00,0x00};
char target = 0x16;
int pos, i, length = 6; // or specify some way to get this number
for(i = 0; i < length; i++)
if(get_res[i] == target) {
pos = i;
break;
}
pos = pos + 1; // as you have to ignore the target itself
char *new_arr = malloc(pos);
for(i = 0; i < length; i++) {
new_arr[i] = get_res[i];
i++;
}
for(i = 0; i < pos; i++)
printf("%c ", new_arr[i]);
return 0;
}

why I am getting segmentation fault with scanf at large inputs

I have written c code to merge sort a array of input
and I tried the code for 2 3 5 10 100 1000 10,000 and 1,000,000
it worked as desired in all cases except the 10,000 and 1,000,000
after debugging I found that the error is within scanf() code
Program received signal SIGSEGV, Segmentation fault.
0x00000000004006a7 in main () at merge.c:10
10 scanf("%i",&array[i]);
but the code is perfectly correct as far as I am concerned
int len;
scanf("%i",&len);
int array[len];
for(int i=0; i<len;i++)
{
scanf("%i",&array[i]);
}
In case you need the full code for clearification here it is
#include <stdio.h>
void mergesort(int* list , int len);
int main()
{
int len;
scanf("%i",&len);
int array[len];
for(int i=0; i<len;i++)
{
scanf("%i",&array[i]);
}
mergesort(array,len);
for(int i=0; i<len;i++) printf("%i\n",array[i]);
printf("\b");
}
void mergesort (int* list, int len)
{
if(len == 1) return;
int i = len/2, j = len-i;
int list1[i], list2[j];
for(int k=0;k<i;k++)
{
list1[k]= list[k];
list2[k]= list[i+k];
}
if(len%2!=0) list2[j-1] = list[len-1];
mergesort(list1 , i);
mergesort(list2 , j);
int k=0,l=0;
// k represent counter over elements in list1
// l represent counter over elements in list2
// k+l represent counte over total elements in list
while(k+l!=len)
{
if(k==i)
{
for(;l<j;l++) list[k+l] = list2[l];
return;
}
else if (l==j)
{
for(;k<i;k++) list[k+l] = list1[k];
}
else if(list1[k]<list2[l])
{
list[k+l]=list1[k];
k++;
}
else if(list1[k]>list2[l])
{
list[k+l] = list2[l];
l++;
}
else
{
//handles dublication
list[k+l] = list1[k];
k++;
list[k+l] = list[l];
l++;
}
}
}
EDIT:
in case you believe that the problem platform dependent I use ubuntu 14.04
and gnu c compiler 4.8.2 and I compile the code with flags -std=c99 -Wall
and it is error and warning free
Merge sort eats plenty of memory, and you're allocating additional memory in what c programmers call stack ( int list1[i], list2[j]; ). And there's actually little room in stack. Doing it over and over again for large values exceeds the limit.
You must use heap allocations instead - dynamic allocations. Heap has plenty of memory available for allocation and is used for large arrays among other purposes. You do it like this:
//C example with malloc, ALWAYS use sizeof
int *array = (int*) malloc( length * sizeof(int));
//C++ way
int *array = new int[length];
But memory remains allocated after the program ends, unless you free it. Which can be a problem in thid case. Make sure to unallocate it when you no longer need it.
//C way
free(array);
//C++ way for arrays
delete[] array;
//C++ way for single heap values
delete value;
This is the right way so you should get used to it as youll need dynamic allocation very much in future.

C String -- Sort by first-word length [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm self-studying C and doing an exercise that, among other things, asks me to sort a list of user-entered strings by length of the first word in the string. The other functions in the exercise (including sorting the string by entire length) were easy to write. I've been working on this one for over three hours and can't get it to work. I'm sorting an array of pointers-to-char, and then printing them with a for loop in the main() function.
There's probably a much easier way to do this, but even if so, I cannot understand why this function doesn't work. I've made about thirty changes to it and the sort still comes out pretty random.
void srtlengthw(char * strings[], int n)
{
int top, seek, ct, ct_temp, i;
int ar_ct[n]
char * temp;
bool inWord;
for (top = 0, ct = 0, i = 0, inWord = false; top < n - 1; top++)
{
while (strings[top][i])
{
if (!isblank(strings[top][i]))
{
i++;
ct++;
inWord = true;
}
else if (!inWord)
i++;
else
break;
}
ar_ct[top] = ct;
for (seek = top + 1, ct = 0, i = 0, inWord = false; seek < n; seek++)
{
while(strings[seek][i])
{
if (!isblank(strings[seek][i]))
{
i++;
ct++;
inWord = true;
}
else if (!inWord)
i++;
else
break;
}
ar_ct[seek] = ct;
if (ar_ct[top] > ar_ct[seek])
{
ct_temp = ar_ct[top];
ar_ct[top] = ar_ct[seek];
ar_ct[seek] = ct_temp;
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
}}
Example of wrong output, as requested:
Input:
Mary
had
a
little
lamb
that
was
sacrificed
to
Satan
=========
Output:
had
a
little
lamb
that
was
sacrificed
to
Mary
Satan
And here's an example of a much simpler function that worked properly. It's meant to sort the pointers by length of the entire string rather than just the first word. I tried to model the word-length sort function on this one, but I'm apparently having trouble dealing with my counter variables and maybe my bool flag right.
void srtlength(char * strings[], int n)
{
int top, seek;
char * temp;
for (top = 0; top < n - 1; top++)
for (seek = top + 1; seek < n; seek++)
if (strlen(strings[top]) > strlen(strings[seek]))
{
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
For Craig, hopefully this helps?
Input:
They say it's lonely at the top, and whatever you do
You always gotta watch m*********s around you
Nobody's invincible
No plan is foolproof
We all must meet our moment of truth
The same sheisty cats that you hang with and do your thang with
Could set you up and wet you up, n***a, peep the language
It's universal
You play with fire, it may hurt you, or burn you
Lessons are blessins you should learn through
Output for me:
You always gotta watch m********s around you
Nobody's invincible
No plan is foolproof
We all must meet our moment of truth
The same sheisty cats that you hang with and do your thang with
Could set you up and wet you up, n***a, peep the language
It's universal
You play with fire, it may hurt you, or burn you
Lessons are blessins you should learn through
They say it's lonely at the top, and whatever you do
If you're looking for output similar to that of the example code that you posted, then I suggest using it as a template for a version with your expected behavior. The key that I'm looking to point out is that it sorts by the return value of the strlen function.
strlen is a function in C's <string.h> library (I think?) that returns the length of a C-style string. In C, as you're probably aware, the end of a string is identified by a null terminator, which is represented as a '\0'.
While the precise strlen may vary from one library to another, here is one standard implementation (made easier to read):
int strlen(char * str){
char * l;
for(l = str; *l != '\0'; l++);
return l - str;
}
People will likely argue that there are problems with this and it isn't perfect, but it does hopefully show how the length of a string is determined.
Now that we understand that the last example sorts by the total string length, and we know how string length is determined, we can probably make our own version of strlen that stops after the first word, instead of stopping at the null terminator:
int blank_strlen(char * str){
char * l;
for(l = str; *l != '\0' && !isblank(*l); l++);
return l - str;
}
Now, using the example code given:
void blank_srtlength(char * strings[], int n)
{
int top, seek;
char * temp;
for (top = 0; top < n - 1; top++)
for (seek = top + 1; seek < n; seek++)
if (blank_strlen(strings[top]) > blank_strlen(strings[seek]))
{
temp = strings[top];
strings[top] = strings[seek];
strings[seek] = temp;
}
}
millinon's answer is a much better way to do it, as it is simpler. However, if you are looking for the reason why your code isn't working, it is due to your variables only being reset outside of each loop.
This code:
for (seek = top + 1, ct = 0, i = 0, inWord = false; seek < n; seek++)
{
while(strings[seek][i])
only sets ct, i and inWord once, before the loop is first started. When the program loops around, the values of ct, i and inWord will be kept from the last iteration.
Moving the assignments inside the loop like this:
for (seek = top + 1; seek < n; seek++)
{
ct = 0;
i = 0;
inWord = false;
while(strings[seek][i])
will fix your problem (you have to do it in both places).

Malloc affecting random integer value

I'm writing a virtual memory simulator in C, compiling on linux, and I'm getting something rather strange. It takes in a file IO, which I put into an int* plist.
I've printed this "plist" array, and it comes out to
0 100
1 200
2 400
3 300
etc
The problem is that it seems malloc or something is randomly changing plist[3] to 0. It doesn't seem like it should be that way, but I've put a print statement at every line of code to print plist[3], and
tables[i].valid = (char*) xmalloc(num_pages * sizeof(char));
is where it changes. plist[3] = 300 before the line, 0 after it. And it only does this when i = 2. The first 3 rounds of the loop run fine, and on round 3, it changes the values for round 4. I have no idea why, it makes little sense that malloc would change a value in an array that's completely unrelated - is it possible I've gone over some space limit, even though I'm using the heap for basically everything? Would it just change values in random arrays if I did?
for(i = 0; i < 4; i++){
num_pages = plist[i] / P1;
tables[i].page_num = (char**) xmalloc(num_pages * sizeof(char*));
tables[i].valid = (char*) xmalloc(num_pages * sizeof(char));
//initialize page numbers and valid bits
for(j = 0; j < 10; j++){
tables[i].page_num[j] = (char*) xmalloc(16*sizeof(char));
tmp = itoa(i, tmp);
strcat(tables[i].page_num[j], tmp);
strcat(tables[i].page_num[j], "p");
tmp = itoa(j, tmp);
strcat(tables[i].page_num[j], tmp);
tables[i].valid[j] = 0;
}
}
Here's the struct for tables:
typedef struct s_page_table
{
char** page_num;
char* valid;
} t_page_table;
And this is xmalloc (it's just a wrapper to make it easier):
void* xmalloc(int s)
{
void* p;
p = malloc(s);
if (p == NULL)
{
printf("Virtual Memory Exhausted");
exit(1);
}
return p;
}
EDIT: If I take out both lines referencing tables[i].valid, the problem does not exist. plist[3] stays the same. num_pages is always >= 10. I set j to be 0 to 10 just to have less output for debugging purposes.
EDIT 2: If I change valid from a char* to an int* it doesn't work. If I change it to an int, it does.
There are several possibilities, including (but not limited to):
tables[i] is out of bounds;
plist contains a dangling pointer (i.e. it's been deallocated);
plist hasn't been initialised;
plist isn't as large as you think, i.e. plist[3] is out of bounds.
If you can't figure out the problem by looking at the code, valgrind is your friend.
OK. So I believe the problem turned out to be playing with the strings before initializing everything. I'm not entirely certain the reason, maybe someone else can elaborate, but when I encapsulated JUST the initialization in its own function, like only doing mallocs, and then separately created the strings afterwards, the plist variable was unaffected.
For those interested, the encapsulated function looked like this:
t_page_table* table_builder(int* p, int x, int num_tables)
{
t_page_table* ret = xmalloc(num_tables * sizeof(*ret));
int i, tmp, j;
for(i = 0; i < num_tables; i++){
tmp = (p[i]/x);
ret[i].page_num = xmalloc(tmp * sizeof(char*));
ret[i].valid = xmalloc(tmp * sizeof(char));
for(j = 0; j < tmp; j++){
ret[i].page_num[j] = xmalloc(16 * sizeof(char));
ret[i].valid = 0;
}
}
return ret;
}

Resources