Segmentation fault (core dumped) c - c

My code is posted below, i'm pretty sure that the segmentation fault is happening in the while loop at the bottom of main().
My program has to read a file, the data is in a grid formation, the fscanf gets teh dimensions of the grid, then creates a 2D array with those dimensions, then i use a while loop to go through line by line and then a for loop to go through character by character in that line to store it in the inner part of the array, then i++ goes to store it in the next level of the 2D array.
can anyone tell me why its doing it?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char direction;
int steps;
int cur[2];
char** gridArray;
int* move(int cur[2]);
int* getCommand(int next[2], char** gridArray);
char** make2DFileArray(int sizeX, int sizeY);
int* makeArray(int size);
int main(int argc, char *argv[] )
{
FILE *fp;
int rows;
int columns;
int i=0,j;
char line[1000];
if ((argc < 2)^(argc > 3)) {
fprintf(stderr, "Usage: thebox mapfile [maxsteps]\n");
exit(1);
}
if( argc < 3 ) { steps = 10; }
else { steps = argv[2]; }
fp = fopen(argv[1], "r");
if( fp == NULL) {
fprintf(stderr, "Missing map file.\n");
exit(1);
}
fscanf(fp, "%d %d", &rows, &columns);
gridArray = make2DFileArray(rows+1, columns);
while ( fgets(line, 1000, fp) != NULL) {
for(j=0; j < columns - 1; j++) {
gridArray[i][j] = line [j];
}
i++;
printf("%s", line);
}
fclose(fp);
printf("(sidepos)>\n");
return 0;
}
and my helper method, is this
char** make2DFileArray(int sizeX, int sizeY)
{
int i;
char** array;
array = (char**) malloc(sizeX*sizeof(char*));
for (i = 0; i < sizeX; i++) {
array[i] = (char*) malloc(sizeY*sizeof(char));
return array;
}
return array;
}
int* makeArray(int size)
{
int* array;
array = (int*) malloc(size*sizeof(int));
return array;
}

The error is in the make2DFileArray function. You just return after the first allocation in the loop, meaning only gridArray[0] will be allocated.
Since none of the other entries will be allocated, accessing e.g. gridArray[1] is undefined behavior and the cause of your crash.

This:
for (i = 0; i < sizeX; i++) {
array[i] = (char*) malloc(sizeY*sizeof(char));
return array;
}
return array;
... should be:
for (i = 0; i < sizeX; i++) {
array[i] = (char*) malloc(sizeY*sizeof(char));
}
return array;
... in your function make2DFileArray.
Remark: The element is allocated memory however the rest of the elements are not because of your return inside the for-loop. Each element in the array from [1 ... length - 1] are random memory addresses (because when you malloc you did not populate them as proper pointers) and hence dereferencing any element other than the one at position 0 will result in undefined behaviour.

steps = argv[2];
The variable 'steps' type is int, and variable 'argv[2]' type is char *, can't be directly assigned.
You can do it by
steps = atoi(argv[2]);

Related

looping array of pointers to free them makes program crash in c

Full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printarray(int* array, int arraysize){
for (int i = 0; i<arraysize; i++){
printf("%d\n", *array);
array++;
}
}
void printStrArray(char** array, int arraysize){
int j = 0;
for (int i = 0; i<arraysize; i++){
j = 0;
while (array[i][j] != '\0'){
printf("%c", array[i][j]);
j++;
}
printf("\n");
}
}
int isStringInArray(char* string, char** stringArray, int arrayLen){ // returns 1 if string is contained in the array.
for (int i = 0; i < arrayLen; i++){
if (strcmp(string, stringArray[i]) == 0){
//printf("%s is equal to %s %d\n", string, stringArray[i], i);
return 1;
}
}
return 0;
}
int lenstring(char* string){ // checks string length (works only if string has null character at the end.)
char currchar = string[0];
int strlen = 0;
while (currchar != '\0'){
strlen++;
currchar = string[strlen];
}
return strlen;
}
char** riassemble(char* stringa){
char** riassembleds = calloc(1, sizeof(char*));
char* charLen = malloc(sizeof(char));
riassembleds[0] = charLen;
int riassembledLen = 1;
int stringalen = lenstring(stringa);
char tempstring[stringalen];
strcpy(tempstring, stringa);
for (int i = 0; i < stringalen; i++){
for (int j = 0; j < stringalen; j++){
tempstring[i] = stringa[j];
tempstring[j] = stringa[i];
//printf("%s\n", tempstring);
if (isStringInArray(tempstring, riassembleds, riassembledLen) == 0){
riassembleds = realloc(riassembleds, (riassembledLen+1)*sizeof(char*));
riassembledLen++;
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
printf("%p\n", riassembleds[riassembledLen-1]);
strcpy(riassembleds[riassembledLen-1], tempstring);
}
strcpy(tempstring, stringa);
}
}
*charLen = (char)riassembledLen;
riassembleds[0] = charLen; /*return the array with the length of the it casted into a char pointer as the first element*/
return riassembleds;
}
int main(int argc, char *argv[]){
char** array = riassemble("ciao");
int arraylen = (int)(*(array[0]));
printf("\n%d\n", arraylen);
printStrArray(array, arraylen);
for (int i=0; i<arraylen; i++) {
free(array[i]);
}
free(array);
return 0;
}
i'm making a function that returns an array of pointers to a char, in which the first element is a pointer that points to the length of the array casted into a char.
When i try to free the elements in the array with
char** array = riassemble("ciao"); /*Creates the array*/
int arraylen = (int)(*(array[0])); /*Gets the length*/
for (int i=0; i<arraylen; i++) {
free(array[i]);
}
The program crashes after trying to free the second element of the array which is defined here:
riassembleds = realloc(riassembleds, (riassembledLen+1)*sizeof(char*));
riassembledLen++;
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
printf("%p\n", riassembleds[riassembledLen-1]);
strcpy(riassembleds[riassembledLen-1], tempstring);
I really don't understand why this happens, one thing i noticed is that if i print the pointers that it's trying to free, they're not the same as when i print them right after allocating them in the riassemble function, but other than that i have no idea what i'm doing wrong.
edit: i was wrong about the fact that they're not the same, they actually are, i got confused.
Your function lenstring will return the length of the string without the terminating null character.
Therefore, the line
char tempstring[stringalen];
will create an array tempstringthat is sufficient in size to store the string stringa without the terminating null character.
However, the function call
strcpy(tempstring, stringa);
requires that tempstring is large enough to store stringa with the terminating null character. You are therefore writing to tempstring out of bounds, invoking undefined behavior.
In order to fix this, I recommend that you change the line
char tempstring[stringalen];
to:
char tempstring[stringalen+1];
The line
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
has the same problem, as it only allocates sufficient space without the terminating null character, which causes the line
strcpy(riassembleds[riassembledLen-1], tempstring);
to invoke undefined behavior for the same reason.
Therefore, the line
riassembleds[riassembledLen-1] = calloc(stringalen, sizeof(char));
should be changed to
riassembleds[riassembledLen-1] = calloc(stringalen+1, sizeof(char));
I was able to find these errors very easily by using AddressSanitizer on your program.

Am I returning double char the correct way?

I am currently practicing malloc and trying to create an array of strings in c.
The following is my little program:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int read_arguments(char*s[]);
char** copy_argv(char*s[]);
void free_char_ary(char*s[]);
int main(int argc, char* argv[])
{
int count = read_arguments(argv);
char **arr = copy_argv(argv);
for(int i = 0; i < count; i++)
{
printf("%s\n", arr[i]);
}
free_char_ary(arr);
exit(0);
}
int read_arguments(char*s[])
{
int count = 0;
while(*s)
{
count++;
s++;
}
return count;
}
char** copy_argv(char*s[])
{
int result = read_arguments(s);
printf("result = %d\n", result);
char** ary = (char**) malloc(result * sizeof(char*));
for(int i = 0; i < result; i++)
{
ary[i] = (char*) malloc(100 * sizeof(char));
strcpy(ary[i], s[i]);
}
return ary;
}
void free_char_ary(char*s[])
{
int count = read_arguments(s);
printf("count = %d\n", count);
for(int i = 0; i < count; i++)
{
free(s[i]);
}
free(s);
}
The result is weird. If i execute for like 4 arguments it is fine, but if i execute with 5 arguments then i get segmentation fault at the free_char_ary. I found that the int returned by read_arguments is different after i copy_argv to char**arr. Am I using the double char pointer the correct way? Why is the result different?
The function free_char_ary has undefined behavior because the dynamically allocated array does not contain an element with the value NULL. As a result the call of read_arguments within the function invokes the undefined behavior.
void free_char_ary(char*s[])
{
int count = read_arguments(s);
printf("count = %d\n", count);
for(int i = 0; i < count; i++)
{
free(s[i]);
}
free(s);
}
You should append the dynamically allocated array with a null pointer the same way as the array argv is defined. Or you could pass to the function the actual number of elements in the dynamically allocated array,

Print last few lines of a text file

Currently, I am trying to create a C program that prints the last few lines of a text file, read in through the command line. However, it is currently causing a segmentation error when I try to copy the strings from fgets into the main array. I have been unable to fix this, and so have not been able to test the rest of my code. How would I begin to fix the segmentation error? I have posted the code below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i=1,j,printNumber;
char **arr = (char **) malloc (100 * sizeof(char *));
char *line = (char *) malloc (80 * sizeof(char));
if (argc == 1) {
printNumber = 10;
}
else {
printNumber = atoi(argv[1]);
}
while (fgets(line,80,stdin) != NULL) {
if (line != NULL) {
line[strlen(line)-1] = '\0';
strcpy(arr[i],line); //SEGMENTATION ERROR!!!!
}
else {
free(line);
strcpy(arr[i],NULL);
}
i++;
printf("%d ",i);
}
free(arr);
for (j = i-printNumber-1; j < i-1; j++) {
printf("%s ", arr[j]);
}
printf("\n");
return 0;
}
You are allocating space for arr, which is a pointer to a pointer to char, but not allocating any individual char * pointers within arr.
Since you allocated arr with the size of 100 * sizeof(char *), I assume you want 100 sub-entries in arr. Sure:
for(i = 0; i < 100; i++)
arr[i] = malloc(80 * sizeof(char));
Then, when you free arr:
for(i = 0; i < 100; i++)
free(arr[i]);
free(arr);
Note that it is good practice to always check malloc for failure (return value of NULL) and handle it, and to set pointers to NULL after freeing them once to avoid double-free bugs.
You don't always know the length of the longest line (not until you try to read) OR how many last lines you are expected to keep track of (but is given at runtime). Thus, both of these values need to be known before you allocate memory or delegated to a function that does it for you.
#include <stdio.h>
#include <stdlib.h>
struct Line {
char *line; // content
size_t storage_sz; // allocation size of line memory
ssize_t sz; // size of line, not including terminating null byte ('\0')
};
int main(int argc, char *argv[]) {
int max_lines = 10;
if (argc > 1) {
max_lines = atoi(argv[1]);
}
if (max_lines < 0) {
fprintf(stderr, "%s\n", "Sorry, no defined behaviour of negative values (yet)\n");
return EXIT_FAILURE;
}
// keep an extra slot for the last failed read at EOF
struct Line *lines = (struct Line *) calloc(max_lines + 1, sizeof(struct Line));
int end = 0;
int size = 0;
// only keep track of the last couple of lines
while ((lines[end].sz = getline(&lines[end].line, &lines[end].storage_sz, stdin)) != -1) {
end++;
if (end > max_lines) {
end = 0;
}
if (size < max_lines) {
size++;
}
}
// time to print them back
int first = end - size;
if (first < 0) {
first += size + 1;
}
for (int count = size; count; count--) {
// lines might contain null bytes we can't use printf("%s", lines[first].line);
fwrite(lines[first].line, lines[first].sz, 1u, stdout);
first++;
if (first > size) {
first = 0;
}
}
// clear up memory after use
for (int idx = 0; idx <= max_lines; idx++) {
free(lines[idx].line);
}
free(lines);
return EXIT_SUCCESS;
}

allocate and fill 2d-array in a function using mpi in C

Im tryin to read a ascii-file consisting of 2 columns of and a variable nr of rows. Reading is done by processor 0 and then the data is distributed using MPI_Bcast(...). I had to create a 1-dim buffer array which contains the data and is sent to all other procs because I haven't found a way to directly broadcast the 2-dim. data.
There's something wrong with the allocation of the array arr. When I try to print the data, the first 3 rows are printed and then I get a segmentation fault. Most likely there are several mistakes.
I really tried to make the example as simple as possible.
my code:
//global variables
...
double **testarray;
int dim;
...
int main(int argc, char **argv){
...
...
read_file("test.txt",&testarray,&dim);
}
int read_file(char* infilename,double ***arr,int *rowsout)
{
FILE* infile;
int i,j,ch,number_of_lines=0;
int rows=0;
//first count lines
if(myid==0) //myid is processor id
{
infile = fopen(infilename, "r");
do
{
ch = fgetc(infile);
if(ch == '\n')
number_of_lines++;
} while (ch != EOF);
if(ch != '\n' && number_of_lines != 0)
number_of_lines++;
//close file
fclose(infile);
rows=number_of_lines-1;
*rowsout=rows;
}
// every proc should know about length of file in order
//to be able to allocate memory
MPI_Bcast(rowsout,1,MPI_INT,0,MPI_COMM_WORLD);
//allocate memory
double *buf; //1D-buffer for 2D-array
MPI_Alloc_mem((*rowsout)*2*sizeof(double), MPI_INFO_NULL, &buf);
MPI_Alloc_mem((*rowsout)*sizeof(double*), MPI_INFO_NULL,arr);
for (i = 0; i < (*rowsout); i++) {
MPI_Alloc_mem(2*sizeof(double),MPI_INFO_NULL,&arr[i]);
}
// Now read file on proc 0
if(myid==0)
{
infile=fopen(infilename,"r");
for(i=0;i<rows;i++)
{
for(j=0;j<2;j++)
{
fscanf(infile,"%lf",arr[i][j]);
printf("arr[%d][%d]:%e\n",i,j,(*arr)[i][j]);
}
}
fclose(infile);
}
return 0;
//dont go further, error occurs before loop finishs
MPI_Bcast(buf,(rows)*2,MPI_DOUBLE,0,MPI_COMM_WORLD);
//now reconstruct array from buffer
for(i=0;i<(*rowsout);i++)
{
for(j=0;j<2;j++)
{
*arr[i][j]=buf[i*2+j];
}
}
MPI_Free_mem(buf);
return 0;
}
You have some issues with your arr as you guessed. Here is a fixed version of your code (minus the MPI stuff):
#include <stdio.h>
#include <stdlib.h>
void read_file(char *filename, double ***arr, int *rowsout);
int main(void)
{
double **testarray;
int dim;
read_file("test.txt", &testarray, &dim);
return 0;
}
void read_file(char *filename, double ***arr, int *rowsout)
{
FILE *infile;
int i, j, ch;
infile = fopen(filename, "r");
do
{
ch = fgetc(infile);
if (ch == '\n')
++*rowsout;
} while (ch != EOF);
rewind(infile);
*arr = malloc(sizeof **arr * *rowsout);
for (i = 0; i < *rowsout; ++i)
(*arr)[i] = malloc(sizeof ***arr * 2);
for (i = 0; i < *rowsout; ++i)
{
for (j = 0; j < 2; ++j)
{
fscanf(infile, "%lf", &(*arr)[i][j]);
printf("(*arr)[%d][%d]: %e\n", i, j, (*arr)[i][j]);
}
}
fclose(infile);
for (i = 0; i < *rowsout; ++i)
free((*arr)[i]);
free(*arr);
}
Example input: test.txt
0.01 0.02
0.3 0.4
5.0 6.0
Example output:
(*arr)[0][0]: 1.000000e-02
(*arr)[0][1]: 2.000000e-02
(*arr)[1][0]: 3.000000e-01
(*arr)[1][1]: 4.000000e-01
(*arr)[2][0]: 5.000000e+00
(*arr)[2][1]: 6.000000e+00
I believe the mistake comes with your fscanf() line. fscanf() wants a double * when you are using "%lf", but you are instead passing arr[i][j] and there's two things wrong with that: since arr is actually a pointer to your 2-D array, you will need to deference it first ((*arr)), and second, since it needs the address of the double, you will need to use &: &(*arr)[i][j].

Print sorted strings from array of strings

I need help with the following program:
Print all sorted strings from the input array of strings.
Assume that strings are sorted if characters are in lexicographic order (also assume that the only characters in strings are letters).
Example:
INPUT:
n=2
1. string: stack
2. string: exchange
OUTPUT:
No sorted strings
I am having a problem with accessing some variables in the following program:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX 30
char** read(int *pn);
int isSorted(char *str);
char** sortedArr(char **str,int pn);
char** read(int *pn)
{
do
{
printf("n = ");
scanf("%d",pn);
}
while(*pn < 1);
char **arr;
arr=(char **)malloc(*pn * sizeof(char *));
int i;
for(i=0; i<*pn;i++)
arr[i]=(char *)malloc(MAX+1);
for(i=0; i<*pn; i++)
{
printf("%d. word: ",i+1);
scanf("%s",arr[i]);
}
return arr;
}
int isSorted(char *str)
{
int i,j;
for(i=0; i<strlen(str)-1;i++)
for(j=i+1; j<strlen(str); j++)
if(strcmp(str+i,str+j) > 0)
return 1;
return 0;
}
char** sortedArr(char **str,int pn)
{
char **sortArr;
sortArr=(char **)malloc(pn * sizeof(char *));
int i;
for(i=0; i<pn; i++)
{
if(isSorted(sortArr[i]))
sortArr[i]=(char *)malloc(MAX+1);
}
for(i=0; i<pn; i++)
{
if(isSorted(sortArr[i]))
printf("%d. word: %s",sortArr+i);
}
return sortArr;
}
int main()
{
char **arr;
char **sortArr;
int pn;
arr=read(&pn);
sortArr=sortedArr(arr,pn);
int i;
for(i=0; i<pn; i++)
free(arr[i]);
free(arr);
return 0;
}
The problem is how to access the variable pn in function sortedArr()?
Your program has several issues, I'll try to address the most part of them.
Let's start from the isSorted function, if your goal is to check if a word has all the character sorted, you don't need to use strcmp or a nested loop. All what you need is something like this:
// check if all the character in the string are sorted
int isSorted( char *str )
{
int i, length = strlen(str) - 1;
for ( i=0; i < length; i++ )
if ( str[i] > str[i+1] )
return 0;
return 1;
}
I'll separate the printing function from the input one and copy ones, so to have:
void print( char **str, int n )
{
int i;
for ( i = 0; i < n; i++ ) {
printf("word %d: %s\n", i + 1, str[i]);
}
}
There are several methods to read some words from stdin and some are presented in other answers. I'll use this, but you should check all the pointers returned from malloc:
char** read(int *pn)
{
char buffer[BUFSIZE];
printf("Please, enter number of words: ");
while ( *pn < 1 && fgets(buffer, BUFSIZE, stdin) ) {
sscanf(buffer, "%d", pn);
}
int i = 0, length;
printf("\nPlease, enter the words: \n");
char **arr = malloc(*pn * sizeof(char *));
while ( i < *pn ) {
// read words one line at a time
if ( !fgets(buffer, BUFSIZE, stdin) )
break;
length = strlen(buffer);
// ignore empty lines
if ( length < 2 )
continue;
arr[i] = malloc(length);
memcpy(arr[i],buffer,length);
// add the null terminator
arr[i][length - 1] = '\0';
++i;
}
*pn = i;
return arr;
}
Then, I'm not really sure if you want only to print the words that are "sorted" or you actually need to copy them (and print later). I'll show you the latter:
// return an array of string containing only the sorted ones
char** sortedArr( char **str, int n, int *m)
{
char **sortArr = NULL;
char *sorted = calloc(n,1);
int i;
*m = 0;
// first find (and count) the sorted strings
for ( i = 0; i < n; i++ ) {
if ( isSorted(str[i]) ) {
// maybe you need only to print str[i] now...
sorted[i] = 1;
++(*m);
}
}
// then copy the sorted. I'm not sure if you need this
int j = 0, length = 0;
if ( *m ) {
sortArr = malloc(*m * sizeof(char *));
for ( i = 0; i < n; i++ ) {
if ( !sorted[i] )
continue;
length = strlen(str[i]) + 1;
sortArr[j] = malloc(length);
memcpy(sortArr[j],str[i],length);
}
}
free(sorted);
return sortArr;
}
Finally the main function (and the one to free allocated memory):
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define BUFSIZE 128
char** read( int *pn );
int isSorted( char *str );
char** sortedArr( char **str, int n, int *m );
void print( char **str, int n );
void freeArr( char **str, int n );
void freeArr( char **str, int n )
{
if ( !str ) return;
int i;
for ( i = 0; i < n; i++ ) {
free(str[i]);
}
free(str);
}
int main()
{
char **arr = NULL;
char **sortArr = NULL;
int n = 0, m = 0;
arr = read(&n);
print(arr, n);
printf("\nSorted: \n");
sortArr = sortedArr(arr,n,&m);
print(sortArr, m);
freeArr(sortArr, m);
freeArr(arr, n);
return 0;
}
Hope it helped. Tell me if there is something wrong or I have misunderstood your task.
Change the sortedArr function, so that it takes pn as an argument:
char** sortedArr(char **str, int pn)...
Then, in your main(), change the sortArr=sortedArr(arr) to sortArr=sortedArr(arr, pn), to pass the value to the function. Then you can use the pn value inside the sortedArr function.
One head-scratcher is:
for(i=0; i<*pn;i++)
arr[i]=(char *)malloc(strlen(arr+i)+1);
for(i=0; i<*pn; i++)
{
printf("%d. word: ",i+1);
scanf("%s",arr[i]);
}
You should combine both because you cannot allocate properly until you know the length of word. Allocating some strlen(arr+i)+1 for who knows what is at arr+i is meaningless (and unless arr+i just happens to be a nul-terminated string, undefined behavior). When you are taking input, you can/should use a temprory buffer to hold the input until you can validate it is what you want it to be. At minimum, test the return to scanf to insure you actually had a sucessful conversion to the type of input you are expecting. For instance:
for (i = 0; i < *pn; i++)
{
char buf[64] = ""; /* however long is sufficient for word */
printf ("%d. word: ",i+1);
if (scanf ("%63[^\n']%*c",buf) == 1)
arr[i] = strdup (buf); /* allocates/copies buf for arr[i] */
else {
fprintf (stderr, "error: invalid input for word[%d].\n", i);
}
}
(note: you have similar allocation issues in sortedArr)
For your sort, you need to pass pn as a parameter to sortedArr so you at least know how many strings you are dealing with. Rather than looping and attempting to compare adjacent elements, why not have your sortedArr function simply call qsort and sort the array you create in read. If you want to preserve both the original and sorted arrays, then have sortedArr call memcpy and create a copy of arr and then call qsort on the copy. All you need to do is create a string comparison compare function for qsort to compare arr or the copy, e.g.:
/* comparison function for qsort (char **) */
int cmp_str (const void *a, const void *b)
{
/* The actual arguments to this function are "pointers to
pointers to char", but strcmp(3) arguments are "pointers
to char", hence the following cast plus dereference
note: to reverse sort order, swap a and b, below */
return strcmp (* (char * const *) a, * (char * const *) b);
}
Which you can then use to sort your arr (or copy) with
qsort (arr, pn, sizeof *arr, cmp_str);
Much less error-prone then a one-off loop and index attempt. Give it a try and let me know if you have questions.

Resources