My multithreaded code is giving wrong results and has segmentation fault - c

I have a program that must take on command-line a file_name, a string string_name (word) and an integer (number of threads) as arguments. Then the program creates those many threads to count the number of times string_name occurs in the file - file_name.
The serial code run properly.
The multithreaded code has following problems:
It leads to core dump - segmentation fault.
It is giving wrong count.
I added some debugging statements:
It is showing wrong line numbers where I am trying to print which line number is being checked by which thread number.
#include <stdio.h>
// #include <conio.h> - Does not exist in gcc
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define MAX_LINE_LENGTH 4096
#define MAX_WORD_SIZE 64
#define MAX_THREAD_COUNT_PER_PROCESS 64
// Important - in GCC - for pthread functions in addition to include pthread.h must also use flag -lpthread in compilation command
// gcc -w -o main main_multithreaded.c -lpthread
typedef unsigned int uint;
typedef struct {
uint valid;
uint line_num;
char* line;
} struct_line;
volatile struct_line buffer[MAX_THREAD_COUNT_PER_PROCESS];
pthread_mutex_t *buffer_mutex;
pthread_t* threads;
typedef struct {
FILE* fp;
} read_pthread_argv_type;
read_pthread_argv_type read_pthread_argv;
void read_file(void* read_pthread_argv)
{
read_pthread_argv_type* i_read_pthread_argv;
i_read_pthread_argv = (read_pthread_argv_type*) read_pthread_argv;
FILE* local_file_ptr;
local_file_ptr = i_read_pthread_argv->fp;
char *line;
uint i, line_count = 0, line_length;
line = (char*) malloc (MAX_LINE_LENGTH);
while (fgets(line, MAX_LINE_LENGTH, local_file_ptr) != NULL)
{
line_length = strlen (line);
while (pthread_mutex_lock(buffer_mutex))
{}
for (i = 0; i<MAX_THREAD_COUNT_PER_PROCESS; i++)
{
if (buffer[i].valid != 1)
{
break;
}
}
buffer[i].line = (char*) malloc (line_length);
buffer[i].line = line;
buffer[i].line_num = line_count;
buffer[i].valid = 1;
// printf ("Line %u of file read and saved as %s \n", buffer[i].line_num, buffer[i].line);
line_count++;
pthread_mutex_unlock(buffer_mutex);
}
printf ("File read finished \n");
free (line);
pthread_exit(NULL);
}
typedef struct {
char* string_to_search;
uint thread_num;
uint count;
} count_pthread_argv_type;
count_pthread_argv_type count_pthread_argv[MAX_THREAD_COUNT_PER_PROCESS];
int count_string (void* pthread_argv_i)
{
// Declare variables for line and word
char *line, *word;
line = (char*) malloc (MAX_LINE_LENGTH);
word = (char*) malloc (MAX_WORD_SIZE);
// Declare and initiaize count
uint count = 0, wordcount_in_line;
uint i, k = 0;
int j;
count_pthread_argv_type* i_pthread_argv;
i_pthread_argv = (count_pthread_argv_type*)pthread_argv_i;
char* local_string_to_search = i_pthread_argv->string_to_search;
uint local_thread_num = i_pthread_argv-> thread_num;
//printf (" For thread %u -> Local string to search = %s \n starting line = %u and num_lines = %u \n", \
local_thread_num, local_string_to_search, local_starting_line, local_num_lines);
//getchar();
while (1)
{
while (pthread_mutex_lock(buffer_mutex))
{}
for (i=0; i < MAX_THREAD_COUNT_PER_PROCESS; i++)
{
if (buffer[i].valid == 1)
{
line = buffer[i].line;
k = buffer[i].line_num;
buffer[i].valid = 0;
printf ("Thread %u checking line %u - which is %s \n", local_thread_num, k, buffer[i].line);
break;
}
}
pthread_mutex_unlock(buffer_mutex);
i = 0, j = 0, wordcount_in_line = 0;
while ( (*(line+i) != '\n') )
{
// Extract word
if ( (*(line+i) == ' '))
{
// NUll terminate the word to make it a string
*(word+j) = '\0';
// Compare
//printf ("Thread %u checking line %u - word number %u which is %s \n", local_thread_num, k, wordcount_in_line, word);
if (strcmp (word, local_string_to_search) == 0) // No double quotes around argv[2]
{
count ++;
printf("Thread %u found its local %uth occurence of %s in line %u at word %u \n", local_thread_num, count, word, k, wordcount_in_line);
}
// Make j = -1, after increment it will be 0 for new word
j = -1;
wordcount_in_line++ ;
}
else
{
*(word+j) = *(line+i);
}
// Increment both i and j to go to next character
i++; j++;
}
if ((*(line + i)) == '\n')
{
// If end of line - do the same thing on last word as is for every word
// NUll terminate the word to make it a string
*(word + j) = '\0';
// Compare
//printf ("Thread %u checking line %u - word number %u which is %s \n", local_thread_num, k, wordcount_in_line, word);
if (strcmp(word, local_string_to_search) == 0) // No double quotes around argv[2]
{
count++;
printf("Thread %u found its local %uth occurence of %s in line %u at word %u \n", local_thread_num, count, word, k, wordcount_in_line);
}
wordcount_in_line++ ;
}
}
void* status;
int rc;
rc = pthread_join (threads[0], &status);
printf ("Thread %u found %u occurences \n", local_thread_num, count);
i_pthread_argv->count = count;
//return (count);
pthread_exit(NULL);
}
int main (int argc, char* argv[])
{
// Declare file *
FILE* fp;
// Get file path and open file
//fp = fopen ("file_name.txt","r");
fp = fopen (argv[1],"r"); // No "" around argv[1]
if (fp == NULL)
{
printf ("fopen failed \n");
return 0;
}
printf ("file = %s and string to look for = %s \n", argv[1], argv[2]);
//fopen_s(&fp, "file_name.txt", "r");
//Initialize mutex
if (pthread_mutex_init(buffer_mutex, NULL))
printf ("Mutex initialization failed \n");
// Get number of lines in file
uint num_threads;
sscanf(argv[3], "%u", &num_threads);
// Create threads
//pthread_t* threads;
threads = (pthread_t*) malloc (sizeof (pthread_t)*MAX_THREAD_COUNT_PER_PROCESS);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
uint i = 0;
read_pthread_argv.fp = fp;
if ( pthread_create (&threads[0], &attr , read_file, (void*)(&read_pthread_argv) ) == 0)
printf("Thread creation %u passed \n", i);
for ( i = 1; i<num_threads; i++ )
{
count_pthread_argv[i].thread_num = i;
count_pthread_argv[i].string_to_search = argv[2];
//printf("Reached debugging point 1 \n");
if ( pthread_create (&threads[i], &attr , count_string, (void*)(&count_pthread_argv[i]) ) == 0)
printf("Thread creation %u passed \n", i);
}
//printf("Reached debugging point 2 \n");
// Doubt 2 - How to call pthread_join to wait for completion of multiple threads -
// Isnt the for loop executed sequentially and pthread_join in main for thread-2 will be executed after thread-1 exits
// Wait till all are over
pthread_attr_destroy(&attr);
void* status;
int rc;
for (i = 1; i<num_threads; i++ )
{
rc = pthread_join (threads[i], &status);
}
uint totalcount = 0;
for (i = 1; i<num_threads; i++)
{
printf ("count_returned = %u \n", count_pthread_argv[i].count);
totalcount += count_pthread_argv[i].count;
}
printf("From main, The file has %s -> %u times", argv[2], totalcount);
for (i=0; i<MAX_THREAD_COUNT_PER_PROCESS; i++)
{
free (buffer[i].line);
}
pthread_mutex_destroy(buffer_mutex);
getchar();
pthread_exit(NULL);
}

Related

Segmentation Fault when using structs in pthreads

I've been trying to split writing to a file with threads and to do so I'm trying to use structs to hold the start and end positions of the file. The code compiles, However, I've been getting a segmentation fault when the code tries to create multiple threads and doesn't execute the thread code. Am I using structs correctly?
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define MAX_THREADS 100
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct position {
int start;
int end;
};
void *ThreadJob(void *id) //what the thread should do
{
pthread_mutex_lock(&mutex);
struct position *b;
printf("\nstart: %d \nend: %d\n", (*b).start, (*b).end);
double* arrayPtr = malloc( 100000* sizeof(double));
FILE *file;
FILE* nFile; // New file
double n;
nFile = fopen("newTriData1.txt","a");
char line[128]; //the lines of the txt file
file = fopen("TriData1.txt", "r");
long tid;
tid = (long)id;
int count = 0;
while (fgets(line, 128, file)) //gets the lines from the txt file - line by line
{
sscanf(line ," %lf", &arrayPtr[count]); //converts the value on the line into a double to manipulate
count++; //increment the count
}
free(arrayPtr);
while((*b).start<(*b).end){
double x = (sqrt(8*arrayPtr[(*b).start]+1) - 1) / 2; //equation to detect triangular numbers
if (x == floor(x)) //checks if the value has a remainder. The value should be a whole number
{
fprintf(nFile, "\nNumber %s: Triangular\n", line); //if true writes the value and triangular
}
else
{
fprintf(nFile, "\nNumber %s: Not Triangular\n", line);
}
(*b).start++;
}
(*b).start=(*b).end;
(*b).end = ((*b).end + (*b).end);
pthread_mutex_unlock(&mutex);
pthread_exit(NULL);
}
int main (void) //main
{
struct position a;
(a).start=0;
int line_count;
FILE *file;
double count_lines = 1.0;
char check;
double i = 4;
file = fopen("TriData1.txt", "r");
double divider;
check = getc(file);
while (check != EOF)
{
if (check == '\n')
{
count_lines = count_lines + 1;
}
check = getc(file); //take the next character from the file
}
printf("cl: %f", count_lines);
double vo = fmod(count_lines,4); //using fmod to find which number divides the line count into equal parts for the number of threads
if (fmod(count_lines,4) == 0) {
double value1 = count_lines/4;
double value2 = count_lines/4;
double value3 = count_lines/4;
double value4 = count_lines/4;
printf("v1: %f \n v2: %f \n v3: %f \n v4: %f", value1,value2,value3,value4);
divider =4;
line_count = count_lines/4;
(a).end=line_count;
}
else
{
while (fmod(count_lines, i) != 0) //if the value is not divisible by 4 then i will increment until a suitable divider is found
{
i++;
divider = i;
line_count = count_lines/i;
printf("divider: %f", divider);
}
(a).end=line_count;
}
fclose(file); //close file.
printf("There are %f lines in this file\n", count_lines);
printf("\nstart: %d \nend: %d\n", (a).start, (a).end);
pthread_t threads[MAX_THREADS];
int thread;
long threadNum ;
for(threadNum=0; threadNum<divider; threadNum++){
printf("Creating thread %ld\n", threadNum);
thread = pthread_create(&threads[threadNum], NULL, ThreadJob, (void *)threadNum);
if (thread){
printf("ERROR; %d\n", thread);
exit(-1);
}
}
pthread_exit(NULL);
return 0;
}
Almost every line of your code is wrong, but most of your mistakes will just make your program do the wrong thing, not crash entirely. Here's just the mistakes that are making your program crash:
struct position *b;
printf("\nstart: %d \nend: %d\n", (*b).start, (*b).end);
That will probably segfault because you can't dereference an uninitialized pointer.
free(arrayPtr);
while((*b).start<(*b).end){
double x = (sqrt(8*arrayPtr[(*b).start]+1) - 1) / 2; //equation to detect triangular numbers
That might segfault because you can't use memory after you free it. Also, the last line of it will probably segfault because you still never initialized b.
(*b).start++;
}
(*b).start=(*b).end;
(*b).end = ((*b).end + (*b).end);
All of those lines will probably segfault because b still isn't initialized.
Frankly, you should give up on advanced topics like threads for now and work on trying to understand the basics of C.

free(): invalid next size(normal)

When running this code with an input .txt file containing somewhere between 200-300 integers (separated by spaces) i get an error right before the for loop with the fprintf statement.
I am not sure if qsort is causing this error or why it occurs but any insight would be appreciated.
(this file is run by adding the name of the input file and the output file in the command line ex: ./program input.txt output.txt
My code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int cmpfunc (const void * a, const void * b)
{
return ( *(int*)a - *(int*)b );
}
int main(int argc, char *argv[]){
if(argc != 3){
printf("\nInvalid input\nPlease provide the input and output text file names as %s name1 name2\n", argv[0]);
}else{
printf("\nPart A: \n");
printf("..............................................................................................................\n\n");
char *fn1 = argv[1]; //variables
char *fn2 = argv[2];
int temp = 0;
int counter = 0;
int index = 0;
int index2 = 0;
int sort = 0;
FILE *fp1 = fopen(fn1, "r"); //read file
FILE *fp2 = fopen(fn2, "w"); //write file
if(fp1 == NULL){ //test if fp1 was opened
printf("There was an error opening the input file");
}
char data[10]; //ints can only hold 10 digits
int *integerArr;
int *tempPointer;
integerArr = malloc(10*sizeof(int));
int sizeOfArrs = 10;
printf("Reading in the textfile: ");
while(fscanf(fp1,"%s",data) != EOF){ //reads in the file breaking on each whitespace and ends at the EOF pointer
temp = strlen(data);
if(temp <=10){
temp = atoi(data);
integerArr[counter] = temp;
printf(".");
counter++;
if(counter == sizeOfArrs -1){
temp = sizeOfArrs * 2;
tempPointer = realloc(integerArr, temp);
if(tempPointer != NULL){
integerArr = tempPointer;
}
}
}else printf("\ninteger had too many digits\n");
}
printf(" Done\n%d Numbers were found\n", counter);
printf("The integers found in the %s file: \n", argv[1]);
index = 0; //reset index to 0;
for(index;index<counter;index++){ //prints the unsorted contents of the file
printf("%d ", integerArr[index]);
}
printf("\n\nPart B\n");
printf("..............................................................................................................\n\n");
printf("The integers found in the %s file after sorting: \n", argv[1]);
qsort(integerArr, counter, sizeof(int), cmpfunc); //best function ever (sorts the array using the cmpfunc to tell if an integer is greater than less than or equal to the next one)
index = 0; //resets the index
for(index; index <counter; index++){ //prints the sorted contents of the file
printf("%d ", integerArr[index]);
fprintf(fp2,"%d ",integerArr[index]); //writes the sorted integers to the new file
}
if(fp2 == NULL){ //tests if the write worked
printf("There was an error writing the outputfile");
}
printf("\n");
close(fp1,fp2); //closes both files
}
return 0;
}
Your fscanf loop is broken. You weren't actually realloc'ing with a larger size. Here's the corrected program [sorry for the pedantic style reedit but you hit one of my nits: long sidebar comments]
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
int
cmpfunc(const void *a, const void *b)
{
return (*(int *) a - *(int *) b);
}
int
main(int argc, char *argv[])
{
if (argc != 3) {
printf("\nInvalid input\nPlease provide the input and output text file names as %s name1 name2\n", argv[0]);
return 1;
}
printf("\nPart A: \n");
printf("..............................................................................................................\n\n");
char *fn1 = argv[1]; // variables
char *fn2 = argv[2];
int temp = 0;
int counter = 0;
int index = 0;
int index2 = 0;
int sort = 0;
FILE *fp1 = fopen(fn1, "r");
FILE *fp2 = fopen(fn2, "w");
// test if fp1 was opened
if (fp1 == NULL) {
printf("There was an error opening the input file");
return 1;
}
// ints can only hold 10 digits
char data[10];
int *integerArr;
int *tempPointer;
int sizeOfArrs = 10;
integerArr = malloc(sizeOfArrs * sizeof(int));
printf("Reading in the textfile: ");
// reads in the file breaking on each whitespace and ends at the EOF
// pointer
while (fscanf(fp1, "%s", data) != EOF) {
temp = strlen(data);
if (temp > 10) {
printf("\ninteger had too many digits\n");
continue;
}
temp = atoi(data);
integerArr[counter] = temp;
printf(".");
counter++;
if (counter == sizeOfArrs - 1) {
sizeOfArrs += 600;
integerArr = realloc(integerArr, sizeOfArrs * sizeof(int));
}
}
// trim array to actual size needed
sizeOfArrs = counter;
integerArr = realloc(integerArr, sizeOfArrs * sizeof(int));
printf(" Done\n%d Numbers were found\n", counter);
printf("The integers found in the %s file: \n", argv[1]);
// prints the unsorted contents of the file
for (index = 0; index < counter; index++) {
printf("%d ", integerArr[index]);
}
printf("\n\nPart B\n");
printf("..............................................................................................................\n\n");
printf("The integers found in the %s file after sorting: \n", argv[1]);
// best function ever (sorts the array using the cmpfunc to tell if an
// integer is greater than less than or equal to the next one)
qsort(integerArr, counter, sizeof(int), cmpfunc);
// prints the sorted contents of the file
for (index = 0; index < counter; index++) {
printf("%d ", integerArr[index]);
// writes the sorted integers to the new file
fprintf(fp2, "%d ", integerArr[index]);
}
// tests if the write worked
if (fp2 == NULL) {
printf("There was an error writing the outputfile");
}
printf("\n");
// closes both files
fclose(fp1);
fclose(fp2);
return 0;
}
Also, note the fclose's at the bottom. There are a few minor bugs left for you to find.

qsort fails to sort large array of strings

I'm using qsort to sort an array of i strings of size 256, such as char *arr = malloc(i * 256) -- was actully done with reallocs inside a loop. Each string contains, among text, a number, which I use as the comparison element:
int
cmp(const void *a, const void *b)
{
double atime = get_time((char*)a);
double btime = get_time((char*)b);
return (atime > btime) - (atime < btime);
}
When i is small, it works. With a large i, it fails to sort the array correctly. get_time is working. I was using it with a custom heapsort implementation before, which worked flawlessly.
I added the following to cmp to check what was happening:
fprintf(stderr, "Comparing %f to %f, result: %d.\n", atime, btime, (atime > btime) - (atime < btime));
It seems that all comparisons are correct, but not all comparisons are being made. arr has several strings containing 1.something, however I couldn't find any comparison between numbers greater than 1 in the output. The call to qsort is as follows:
qsort((void*)arr, i-1, MAX_ROW_LEN, cmp);
It's the same parameters I used to pass to my heapsort function, but it doesn't work.
Complete code, and example file (fails to sort).
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define MAX_ROW_LEN 256
#define MAX_FILENAME_LEN 256
/* Return the start time of the event or -1 if no time. */
static double
get_time(const char *event)
{
if (!event || event[0] == '%')
return -1;
size_t tok = strcspn(event, " ") + 2;
double ans = strtod(event + tok, NULL);
if (!ans)
return -1;
return ans;
}
/*static inline*/ int
cmp(const void *a, const void *b)
{
double atime = get_time((char*)a);
double btime = get_time((char*)b);
return (atime > btime) - (atime < btime);
}
int
main(int argc, char **argv)
{
/* process parameters */
if (argc < 2) {
fprintf(stderr, "Supply a file to sort.\n");
exit(EXIT_FAILURE);
}
if (strlen(argv[1]) > MAX_FILENAME_LEN) {
fprintf(stderr, "Filename too long.\n");
exit(EXIT_FAILURE);
}
/* read the file */
printf("Now processing %s.\n", argv[1]);
FILE *f = fopen(argv[1], "r");
if (!f) {
fprintf(stderr, "Failed to open out. Errno %d.\n", errno);
exit(EXIT_FAILURE);
}
char *trace = malloc(MAX_ROW_LEN);
char *header = malloc(MAX_ROW_LEN);
size_t i = 1, j = 1;
while (fgets(trace + (i-1)*MAX_ROW_LEN, MAX_ROW_LEN, f)) {
/* (if we can't get the time, it's part of the header) */
if (get_time(trace + (i-1)*MAX_ROW_LEN) != -1) {
trace = realloc((void*)trace, (++i)*MAX_ROW_LEN);
} else {
strncpy(header + (j-1)*MAX_ROW_LEN, trace + (i-1)*MAX_ROW_LEN,
MAX_ROW_LEN);
header = realloc((void*)header, (++j)*MAX_ROW_LEN);
}
}
if (!feof(f)) {
fprintf(stderr, "Error reading file. Errno %d.\n", ferror(f));
exit(EXIT_FAILURE);
}
printf("Read %zu lines.\n", i);
fclose(f);
/* write the header */
f = fopen("out_fixed", "w");
if (!f) {
fprintf(stderr, "Failed to open out_fixed. Errno %d.\n", errno);
exit(EXIT_FAILURE);
}
for (size_t k = 0; k < j-1; ++k) {
/* (there is '%' in comments, can't print formatted) */
fputs((void*)(header + k*MAX_ROW_LEN), f);
}
/* sort */
printf("Started sorting.\n");
time_t start = time(NULL);
qsort((void*)trace, i-1, MAX_ROW_LEN, cmp);
printf("Ended sorting, took %fs.\n", difftime(time(NULL), start));
/* write the sorted trace */
printf("Started writting to disk.\n");
start = time(NULL);
for (size_t k = 0; k < i-1; ++k) {
fprintf(f, "%s", trace + k*MAX_ROW_LEN);
}
printf("Took %fs.\n", difftime(time(NULL), start));
/* flush */
printf("Closing file (fflush)\n");
start = time(NULL);
if (fclose(f)) {
fprintf(stderr, "Failed to close out_fixed. Errno %d.\n", errno);
exit(EXIT_FAILURE);
}
printf("Took %fs.\n", difftime(time(NULL), start));
exit(EXIT_SUCCESS);
}
I've tested your code and your example input file and it seems to work fine. In your question you say:
... has several strings containing 1.something, however I couldn't find
any comparison between numbers greater than 1 in the output.
But there are no such lines in your example input file.
Given this example line of your input:
12 0.475183170 rank3 STATE fill_row
This line in get_time is going to skip over any leading digits in your double:
size_t tok = strcspn(event, " ") + 2;
strcspn returns the number of characters that it had to read before finding the "needle" so in this case it will return 2. You then add 2 to that and then use that as a pointer offset into your event string, meaning that you are passing a pointer to .475183170 instead of 0.475183170.
You'd be better off just using strchr here anyway:
char *tok = strchr(event, ' ');
if (!tok) {
return -1;
}
double ans = strtod(tok, NULL);
The subsequent strtod will skip leading whitespace for you, so you don't need to get super fancy.

C segmentation fault when I try to printf just after printing the first value inside function

I am getting segmentation fault when I try to use printf on *buffer[i] in readWav() function. And buffer was able to correctly pass to main() and I was able to check values in main with datas[i]. I simply copied the printf in main() and had to replace datas[i] with *buffer[i] then it compiles fine. It prints the first value in readWav() and then SegFault occurs.
How do I do this in readWav() - What is wrong with *buffer[i]) - in other words, if datas[i] refers to actual values in main() what would that be in readWav() in terms of buffer?
Update:
main() will pass datas to other functions still to be added on. That is why I tried printing it in readWav() thinking it will be very similar in how values are passed on to other functions - please correct me if I am wrong?
#include <stdio.h>
#include "sndfile.h"
int readWav(const char *const fname, long *numFrames, int *sRate, float **buffer);
int main(int argc, char *argv[])
{
int sRates, sRatem, ret;
long nSamples = 0, nSamplem;
float *datas, *datam;
printf("Read Test\n");
if (argc != 3) {
fprintf(stderr, "Expecting two wav file as argument\n");
return 1;
}
ret = readWav(argv[1], &nSamples, &sRates, &datas);
if (ret != 0) {
printf("Error\n");
return 1;
}
// Output Info
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
nSamples, argv[1], sRates, (float)nSamples/sRates);
for (i=0; i < nSamples ; i++) {
printf("%d\t %f\n", i, datas[i]);
}
free(datas);
return 0;
//Cleanup etc:
}
int readWav(const char *const fname, long *numFrames, int *sRate, float **buffer)
{
// Open sound file
SF_INFO sndInfo;
if ((sRate == NULL) || (numFrames == NULL) || (buffer == NULL)) {
fprintf(stderr, "Invalid arguments passed to readWav()\n");
return 1;
}
SNDFILE *sndFile = sf_open(fname, SFM_READ, &sndInfo);
if (sndFile == NULL) {
fprintf(stderr, "Error reading source file '%s': %s\n", fname, sf_strerror(sndFile));
return 1;
}
// Allocate memory
*buffer = malloc(sndInfo.frames * sndInfo.channels * sizeof(float));
if (*buffer == NULL) {
fprintf(stderr, "Could not allocate memory for file\n");
sf_close(sndFile);
return 1;
}
*sRate = sndInfo.samplerate;
// Load data
*numFrames = sf_readf_float(sndFile, *buffer, sndInfo.frames);
// Check correct number of samples loaded
if (*numFrames != sndInfo.frames) {
fprintf(stderr, "Did not read enough frames for source\n");
sf_close(sndFile);
free(*buffer);
}
else {
printf("Successfully read file\n");
*numFrames = sndInfo.frames;
}
// Output Info
printf("Read %ld frames from %s, Sample rate: %d, Length: %fs\n",
*numFrames, fname, *sRate, (float)*numFrames/sndInfo.samplerate);
for (i=0; i < sndInfo.frames ; i++) {
printf("%d\t %f\n", i, *buffer[i]);
}
sf_close(sndFile);
return(0);
}
You are accessing an array index BEFORE derefencing the pointer.
You meant to do (*buffer)[i], but did *(buffer[i]) instead (notice how I added the parenthesis for clarity).
Next time, remember that * has a lower precedence than [].

c, 2d char array and fopen

I'm trying to make a program that reads a file with list of names. The number of those names can vary, as well as the names lengths. I want to store them in an array of arrays of char, and read each row as a string to later open the file that corresponds to the name in question. But when I try to open the first one, I have an error opening file.
I'm totally out of ideas.
Help, please?
Here is the code relevant to this action:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
int glimps(char *fname);
int write_av(char *fname, int NumbFiles);
int clr(char *fname);
int readFile(char *fname, int i);
double *dalpha, *alpha, *Ln_t, *LnLnA, Conc;
long *time, *weights, *Lmax, Nmax;
char *av_file, **in_files, *antetka;
/****************************************************************************/
int main(int argc, char *farg[])
{
int i, NumbFiles, flag;
long row;
char *a1;
FILE *fp;
av_file = farg[1];
printf("av_file = %s\n",av_file);
NumbFiles = glimps(av_file);
in_files = (char **) malloc (sizeof(char *) * NumbFiles);
for (i=0 ; i<NumbFiles ; i++)
in_files[i] = (char *) malloc (sizeof(char) * 200);
Lmax = (long *) calloc((size_t) NumbFiles, sizeof(long));
if((in_files == NULL)||(Lmax==NULL)) printf("Грешка при read алок.\n, "), exit(-1);
if (flag = readFile(av_file, -1))
printf("Error in read av_file %s\n", av_file), exit(-1);
weights = (long *) calloc((size_t) Nmax, sizeof(long));
for(i = 0; i<Nmax; i++) weights = 0;
for(i = 0; i<NumbFiles; i++)
{
//if (flag = readFile(&(*in_files[i]), i))
if (flag = readFile(in_files[i], i))
printf("Error in in_files[%d], %s\n",i, &(*in_files[i])), exit(-1);
}
if (flag = write_av(av_file, NumbFiles))
printf("Error in write_av(%s)\n,", av_file), exit(-1);
exit(0);
}
/****************************************************************************/
int glimps(char *fname)
{
FILE *fp;
char buf[140];
int cnt=0;
fp = fopen (fname, "r");
while (fgets(buf,140,fp) )
{
cnt++;
}
fclose(fp);
return (cnt);
}
/****************************************************************************/
int readFile(char *fname, int k)
{
int cnt=0;
FILE *fp;
char buf[200], dummy[13];
printf("fname is %s\n", fname); getchar();
fp = fopen (fname, "r");
if(fp==(NULL)) return(-1);
if(!strcmp(fname,av_file) )
{
while (fgets(in_files[cnt++],200,fp) );
}
else
{
printf("read TUK!\n"); getchar();
fgets(buf,200,fp);
sscanf(buf,"%s %s %s %s %s %s %s %ld %s %s %lf\n",
dummy, dummy,dummy,dummy,dummy,dummy,dummy, &Lmax[k],
dummy, dummy, &Conc);
fgets(buf,200,fp);
sscanf(buf,"%s\n", antetka);
printf("read TUK!\n"); getchar();
while (fgets(buf,200,fp))
{
sscanf(buf,"%ld %lf %lf %s %lf %lf\n",
&time[cnt], &dalpha[cnt], &alpha[cnt], dummy, &Ln_t[cnt],
&LnLnA[cnt]);
weights[cnt++]++;
}
}
fclose(fp);
return (0);
}
...
Console Output:
> ./avr alpha_cubeL.C0.010
av_file = alpha_cubeL.C0.010
fname is alpha_cubeL.C0.010
fname is alpha_cubeL100C0.010
Error in read in_files[0], alpha_cubeL100C0.010
> ls alpha_cubeL100C0.010
alpha_cubeL100C0.010
What happens is that in the readFile function, you read the main file given as argument to make (from the content) several file names in in_files[i], but fgets reads lines including the CR or CRLF (ie the end of line character(s)). Thus later in the program, readFile fails as it tries to open filename + CR [LF].
You may just add a trim function near the top of your program, like
void trim(char *s) {
int i,l = strlen(s);
for (i=l-1 ; i>=0 && (s[i]==10 || s[i]==13) ; i--) s[i] = 0;
}
that removes CR and/or LF that end a string s, and then change the readFile function to trim the file names read in each line, like
while (fgets(in_files[cnt++],200,fp) ) {
trim(in_files[cnt-1]); // cnt-1, or do the cnt++ here (and not above...)
}
Then the files can be opened...
(this is probably not the only problem in this program, but this is a good start)

Resources