Segmentation fault always occurs after 3 inputs - c

I have the following code to accept any number of lines from the user and print out the ones whose length is > 80 characters :-
#include <stdio.h>
#include <stdlib.h>
#include "shared.h"
#include <string.h>
int MAXLINE = 10;
int INCREMENT = 10;
int NUM = 1;
char* longest = NULL;
char* line = NULL;
char** row = NULL;
void _memcleanup(){
int i =0;
free(line);
free(longest);
for(i=0;i<NUM;i++){
free(row[i]);
}
free(row);
}
void print_lines(int len){
int i;
for(i=0;i<len;i++){
if(strlen(row[i])>80){
printf("%s\n",row[i]);
}
}
}
void copy(char** longest, char** line){
int i=0;
char* temp = realloc(*longest,(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*longest = temp;
while(((*longest)[i] = (*line)[i]) != '\0'){
++i;
}
longest[i] = '\0';
}
void store(char** s, int pos){
int i=0;
char* temp = realloc(row[pos],(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
row[pos] = temp;
while((row[pos][i] = (*s)[i]) != '\0'){
++i;
}
row[pos][i] = '\0';
}
int _getline(char** s, int pos){
int i,c;
for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
if(i == MAXLINE - 2){
char* temp = realloc(*s,(MAXLINE + INCREMENT)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*s= temp;
MAXLINE += INCREMENT;
}
(*s)[i] = c;
}
if(c == '\n'){
(*s)[i++] = c;
}
(*s)[i]= '\0';
store(s, pos);
return i;
}
int main(){
int max=0, len, i=0;
line = malloc(MAXLINE*sizeof(char));
longest = malloc(MAXLINE*sizeof(char));
//array of character pointers
row = malloc(NUM*sizeof(char*));
//allocate memory for each row in the array
for(i = 0; i < NUM; i++){
row[i]= malloc(MAXLINE*(sizeof(char)));
}
i=0;
//for(i=0; len = _getline(&line)) > 0; i++){
while((len = _getline(&line, i)) > 0){
printf("%d %d", len, MAXLINE);
/* if(len > max){ */
/* max = len; */
/* copy(&longest, &line); */
/* } */
i++;
}
/* if(max>0){ */
/* printf("%s",longest); */
/* } */
print_lines(i);
_memcleanup();
return 0;
}
The idea that i am following is to reallocate the 2D array when the number of lines exceed NUM. Now to test it out, i set NUM as 1. However, even after doing so, the program gladly accepts upto 3 inputs and segfaults on the 4th input i.e. pos=3 in the program's context.
Why does it accept 3 inputs (ideally it should give a segfault pos=1 itself since i have given size as only 1 and i am not allocating more space for the 2D array)
Working code is as follows:
#include <stdio.h>
#include <stdlib.h>
#include "shared.h"
#include <string.h>
int MAXLINE = 10;
int INCREMENT = 10;
int NUM = 1;
char* longest = NULL;
char* line = NULL;
char** row = NULL;
void _memcleanup(){
int i =0;
free(line);
free(longest);
for(i=0;i<NUM;i++){
free(row[i]);
}
free(row);
}
void print_lines(int len){
int i;
for(i=0;i<len;i++){
if(strlen(row[i])>80){
printf("%s\n",row[i]);
}
}
}
void copy(char** longest, char** line){
int i=0;
char* temp = realloc(*longest,(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*longest = temp;
while(((*longest)[i] = (*line)[i]) != '\0'){
++i;
}
longest[i] = '\0';
}
void store(char** s, int pos){
int i=0;
if(pos == NUM){
char** temprow = realloc(row, (NUM + INCREMENT)*sizeof(char*));
if(temprow == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
row = temprow;
//allocate space for extra elements
for(i=NUM;i<NUM+INCREMENT;i++){
row[i] = malloc(MAXLINE*sizeof(char));
}
NUM = NUM + INCREMENT;
}
char* temp = realloc(row[pos],(MAXLINE)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
row[pos] = temp;
while((row[pos][i] = (*s)[i]) != '\0'){
++i;
}
row[pos][i] = '\0';
}
int _getline(char** s, int pos){
int i,c;
for(i=0; ((c=getchar())!=EOF && c!='\n'); i++){
if(i == MAXLINE - 2){
char* temp = realloc(*s,(MAXLINE + INCREMENT)*sizeof(char));
if(temp == NULL){
printf("%s","Unable to allocate memory");
_memcleanup();
exit(1);
}
*s= temp;
MAXLINE += INCREMENT;
}
(*s)[i] = c;
}
if(c == '\n'){
(*s)[i++] = c;
}
(*s)[i]= '\0';
store(s, pos);
return i;
}
int main(){
int max=0, len, i=0;
line = malloc(MAXLINE*sizeof(char));
longest = malloc(MAXLINE*sizeof(char));
//array of character pointers
row = malloc(NUM*sizeof(char*));
//allocate memory for each row in the array
for(i = 0; i < NUM; i++){
row[i]= malloc(MAXLINE*(sizeof(char)));
}
i=0;
//for(i=0; len = _getline(&line)) > 0; i++){
while((len = _getline(&line, i)) > 0){
printf("%d %d", len, MAXLINE);
/* if(len > max){ */
/* max = len; */
/* copy(&longest, &line); */
/* } */
i++;
}
/* if(max>0){ */
/* printf("%s",longest); */
/* } */
print_lines(i);
_memcleanup();
return 0;
}

You are asking:
Why does it accept 3 inputs (ideally it should give a segfault pos=1 itself since i have given size as only 1 and i am not allocating more space for the 2D array)
and you are right, that if you allocate memory for one row only, it invokes Undefined Behaviour if you attempt to access rows[1]. But that behaviour is just -- undefined -- what means that you can't rely on the program crashing. Anything might happen, including that the program seems to work flawlessly

In the main(), instead of using
while((len = _getline(&line, i)) > 0){
use
while(i< NUM)
{
len = _getline(&line, i);
For me with this code change, it worked correctly.

Related

Why on while(getchar()!=EOF) it iterates extra time?

I'm trying to count chars from input, and I noticed that while(getchar()!=EOF) produces an extra count, Is it because it counts the null-terminated from input?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define LINE 5
#define MEM_SIZE 10
char *getInput(int *counter);
void printInput(char *input);
int main() {
char *mainInput;
int counter = 0;
printf("Please enter your input:\n");
mainInput = getInput(&counter);
if (mainInput == NULL) {
return 1;
}
printf("\n\n\nOutput:\n%s\n", mainInput);
printf("number of chars: %d\n", counter);
printInput(mainInput);
free(mainInput);
return 0;
}
char *getInput(int *counter) {
char *p = (char *)malloc(MEM_SIZE * sizeof(char));
char *q = p; /* backup pointer, if realloc fails to allocate, function will return last address values stored */
int c;
int temp_counter = 0;
long current = 0, last = MEM_SIZE - 1;
while ((c = getchar()) != EOF) {
if (current >= last) {
q = p;
p = (char *)realloc(q, last + (MEM_SIZE * sizeof(char)));
if (p == NULL) {
printf("Memory allocation failed, printing only stored values \n");
return q;
}
last += MEM_SIZE;
}
p[current] = c;
temp_counter++;
printf("number of chars: %d\n", temp_counter);
++current;
}
p[current] = '\0';
(*counter) = temp_counter - 1;
return p;
}
void printInput(char *input) {
int i, j = 0;
while (input[j] != '\0') {
for (i = 0; i < LINE; i++) {
if (input[j] == '\0')
break;
putchar(input[j]);
++j;
}
if (input[j] != '\0')
putchar('\n');
}
}

how to fill an array of pointers in c

I want to fill an array of char pointers in the following format:
[name, number of email addresses, all the email addresses]*number of people. The number of mail adresses for each person isn't known at first.
I have to use char *contacts[N]
When printing the array it only prints contacts[0], so I guess my way of scanning the input is wrong
This is my main so far:
int main()
{
char *contacts[N];
int nextAvailable = 0;
int * const nextAvailableP = &nextAvailable;
add(contacts, nextAvailableP);
//Printing this way will only print contacts[0]
int i;
for (i = 0; i < nextAvailable; i++) {
printf("%s", contacts[i]);
}
}
This is the add function:
int add(char *contacts[], int *nextAvailableP) {
if (*nextAvailableP > 97) {
printf("Not enough memory\n");
return FALSE;
}
char tempName[50];
char tempMail[50];
int numberOfMails = 1;
printf("Enter your name\n");
fgets(tempName, 50, stdin);
if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
tempName[strlen(tempName) - 1] = '\0';
contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory\n");
return FALSE;
} else {
strcpy(contacts[*nextAvailableP], tempName);
}
(*nextAvailableP)++;
int numberOfMailsIndex = *nextAvailableP;
itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
(*nextAvailableP)++;
printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
fgets(tempMail, 50, stdin);
while (strcmp(tempMail, "-1") != 0) {
if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
tempMail[strlen(tempMail) - 1] = '\0';
}
contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory");
return FALSE;
} else {
strcpy(contacts[*nextAvailableP], tempMail);
}
(*nextAvailableP)++;
numberOfMails++;
itoa(numberOfMails, contacts[numberOfMailsIndex], 10);
fgets(tempMail, 50, stdin);
}
}
I thought I was initializing each cell in contacts to the requested size and then copying the word I scan from the user into it - but obviously I'm not. Should I iterate through each memory I've allocated char by char?
Btw, I know that the casting to *char isn't necessary
So this would be your corrected code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ENTRIES 50
int add(char *contacts[], int *nextAvailable);
int main(void){
int i;
char *contacts[MAX_ENTRIES];
int nextAvailable = 0;
add(contacts, &nextAvailable);
add(contacts, &nextAvailable);
for(i=0; i < nextAvailable ; i++){
printf("%s\n", contacts[i]);
}
}
char* intToString(int val, int base){
//source: www.strudel.org.uk/itoa/
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}
int add(char *contacts[], int *nextAvailableP) {
if (*nextAvailableP > 97) {
printf("Not enough memory\n");
return 0;
}
char tempName[50];
char tempMail[50];
int numberOfMails = 1;
printf("Enter your name\n");
fgets(tempName, 50, stdin);
if ((strlen(tempName) > 0) && (tempName[strlen(tempName) - 1] == '\n'))
tempName[strlen(tempName) - 1] = '\0';
contacts[*nextAvailableP] = (char *)malloc((strlen(tempName) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory\n");
return 0;
} else {
strcpy(contacts[*nextAvailableP], tempName);
}
(*nextAvailableP)++;
int numberOfMailsIndex = (*nextAvailableP);
contacts[numberOfMailsIndex] = malloc(5);
(*nextAvailableP)++;
printf("Enter your mail/s, use enter to enter a mail and '-1' to signal you finished\n");
fgets(tempMail, 50, stdin);
while (strcmp(tempMail, "-1\n") != 0) {
if ((strlen(tempMail) > 0) && (tempMail[strlen(tempMail) - 1] == '\n')) {
tempMail[strlen(tempMail) - 1] = '\0';
}
contacts[*nextAvailableP] = (char *)malloc((strlen(tempMail) + 1));
if (contacts[*nextAvailableP] == NULL) {
printf("Not enough memory");
return 0;
} else {
strcpy(contacts[*nextAvailableP], tempMail);
}
(*nextAvailableP)++;
numberOfMails++;
fgets(tempMail, 50, stdin);
}
strcpy(contacts[numberOfMailsIndex], intToString(numberOfMails - 1,10));
}
Your function add could be cut in a subfunction which gets a string from the user. This string will be stored in a allocated memory space which has the size of string.
Keep in mind : It's not a good practice to mix data of different nature in one array (names and email). It would be better to use structs (as #Barmar said).
I would do following steps:
Get name from user (char *)
Allocate memory and copy the name into it.
insert the pointer to this allocated memory into your array (contacts)
Get a email address put it in a dynamic allocated memory space
add its pointer to your array (Contacts
Increment emails counter
repeat
-1 detected
convert your email counter to string and the pointer into your array
Anyway here's a code that you can start play with:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_ENTRIES 50
#define BUFFERSIZE 50
int add(char *contacts[], int *nextAvailable);
char *getString(char *queryText);
char* intToString(int val, int base);
int main(void){
int i;
char *contacts[MAX_ENTRIES];
int nextAvailable = 0;
add(contacts, &nextAvailable);
add(contacts, &nextAvailable);
for(i=0; i < nextAvailable ; i++){
printf("%s", contacts[i]);
}
}
int add(char *contacts[], int *nextAvailable){
if(*nextAvailable > MAX_ENTRIES - 1){
printf("Not enough memory\n");
return 1;
}
contacts[*nextAvailable] = getString("Enter your name\n");
if(contacts[*nextAvailable] == NULL){
printf("Malloc Error\n");
return 1;
}
++(*nextAvailable);
int counterfield = *nextAvailable;
++(*nextAvailable);
int emailCounter = 0;
while(1){
if(*nextAvailable > MAX_ENTRIES - 1){
printf("Not enough memory\n");
return 1;
}
char *email = getString("Enter email\n");
if(strcmp(email, "-1\n") == 0){
contacts[counterfield] = malloc(5);
contacts[counterfield] = intToString(emailCounter, 10);
return 0;
}
emailCounter++;
contacts[*nextAvailable] = email;
++(*nextAvailable);
}
}
char *getString(char *queryText){
char buffer[BUFFERSIZE];
char *ret;
printf("%s", queryText);
fgets(buffer, BUFFERSIZE, stdin);
ret = malloc(strlen(buffer));
strcpy(ret, buffer);
return ret;
}
char* intToString(int val, int base){
//source: www.strudel.org.uk/itoa/
static char buf[32] = {0};
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}

To mimic sort command of linux, to sort lines of a text file

Sort command of linux must sort the lines of a text file and transfer the output to another file. But my code gives a runtime error. Please rectify the pointer mistakes so that output.
In which line exactly should I make changes? Because there is no output after all.
I'm pasting the whole code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sortfile(char **arr, int linecount) {
int i, j;
char t[500];
for (i = 1; i < linecount; i++) {
for (j = 1; j < linecount; j++) {
if (strcmp(arr[j - 1], arr[j]) > 0) {
strcpy(t, arr[j - 1]);
strcpy(arr[j - 1], arr[j]);
strcpy(arr[j], t);
}
}
}
}
int main() {
FILE *fileIN, *fileOUT;
fileIN = fopen("test1.txt", "r");
unsigned long int linecount = 0;
int c;
if (fileIN == NULL) {
fclose(fileIN);
return 0;
}
while ((c = fgetc(fileIN)) != EOF) {
if (c == '\n')
linecount++;
}
printf("line count=%d", linecount);
char *arr[linecount];
char singleline[500];
int i = 0;
while (fgets(singleline, 500, fileIN) != NULL) {
arr[i] = (char*)malloc(500);
strcpy(arr[i], singleline);
i++;
}
sortfile(arr, linecount);
for (i = 0; i < linecount; i++) {
printf("%s\n", arr[i]);
}
fileOUT = fopen("out.txt", "w");
if (!fileOUT) {
exit(-1);
}
for (i = 0; i < linecount; i++) {
fprintf(fileOUT, "%s", arr[i]);
}
fclose(fileIN);
fclose(fileOUT);
}
The problem in your code is you do not rewind the input stream after reading it the first time to count the number of newlines. You should add rewind(fileIN); before the next loop.
Note however that there are other problems in this code:
the number of newline characters may be less than the number of successful calls to fgets(): lines longer than 499 bytes will be silently broken in multiple chunks, causing more items to be read by fgets() than newlines. Also the last line might not end with a newline. Just count the number of successful calls to fgets().
You allocate 500 bytes for each line, which is potentially very wasteful. Use strdup() to allocate only the necessary size.
Swapping the lines in the sort routine should be done by swapping the pointers, not copying the contents.
allocating arr with malloc is safer and more portable than defining it as a variable sized array with char *arr[linecount];
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void sortfile(char **arr, int linecount) {
for (;;) {
int swapped = 0;
for (int j = 1; j < linecount; j++) {
if (strcmp(arr[j - 1], arr[j]) > 0) {
char *t = arr[j - 1];
arr[j - 1] = arr[j];
arr[j] = t;
swapped = 1;
}
}
if (swapped == 0)
break;
}
}
int main() {
FILE *fileIN, *fileOUT;
char singleline[500];
int i, linecount;
fileIN = fopen("test1.txt", "r");
if (fileIN == NULL) {
fprintf(stderr, "cannot open %s\n", "test1.txt");
return 1;
}
linecount = 0;
while (fgets(singleline, 500, fileIN)) {
linecount++;
}
printf("line count=%d\n", linecount);
char **arr = malloc(sizeof(*arr) * linecount);
if (arr == NULL) {
fprintf(stderr, "memory allocation failure\n");
return 1;
}
rewind(fileIN);
for (i = 0; i < linecount && fgets(singleline, 500, fileIN) != NULL; i++) {
arr[i] = strdup(singleline);
if (arr[i] == NULL) {
fprintf(stderr, "memory allocation failure\n");
return 1;
}
}
fclose(fileIN);
if (i != linecount) {
fprintf(stderr, "line count mismatch: i=%d, lilnecount=%d\n",
i, linecount);
linecount = i;
}
sortfile(arr, linecount);
for (i = 0; i < linecount; i++) {
printf("%s", arr[i]);
}
fileOUT = fopen("out.txt", "w");
if (!fileOUT) {
fprintf(stderr, "cannot open %s\n", "out.txt");
return 1;
}
for (i = 0; i < linecount; i++) {
fprintf(fileOUT, "%s", arr[i]);
}
fclose(fileOUT);
for (i = 0; i < linecount; i++) {
free(arr[i]);
}
free(arr);
return 0;
}
To get a different sort order, you would change the comparison function. Instead of strcmp() you could use this:
#include <ctype.h>
int my_strcmp(const char *s1, const char *s2) {
/* compare strings lexicographically but swap lower and uppercase letters */
unsigned char c, d;
while ((c = *s1++) == (d = *s2++)) {
if (c == '\0')
return 0; /* string are equal */
}
/* transpose case of c */
if (islower(c)) {
c = toupper(c);
} else {
c = tolower(c);
}
/* transpose case of d */
if (islower(d)) {
d = toupper(d);
} else {
d = tolower(d);
}
/* on ASCII systems, we should still have c != d */
/* return comparison result */
if (c <= d)
return -1;
} else {
return 1;
}
}

Base change program in C complies but does not show any output

I'm recently new to programming but this assignment has proven to be my most difficult. The program is suppose to read in a .txt file with the following format
input_base number output_base
and outputs the results. the bases can only range from 2-36 For example:
input: 2 10 4
output: 2
My program reads in each part of the line and stores them respectively. I then go through the steps to convert the number into the output base and then print it backwards. My problem is that the program runs fine and prints all the stored values and calculated values, but once I add in my "base_conversion" function the program no longer works and my friend even said it gave him a segmentation fault. I don't really know what could be causing it. Any help would be appreciated. Thank you.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void read_file_to_buffer(FILE *file);
char *buffer = NULL;
void string_check(char *buffer);
int char_to_int(char c);
int int_conversion(int x, int y);
void base_conversion(int end_number, int out_base);
int main(int argc, char *argv[]){
FILE *file = NULL;
if ( argc != 2 ){
fprintf(stderr, "Error: To many/few arguments\n");
exit(EXIT_FAILURE);
}
else {
file = fopen(argv[1], "rb");
if (file == NULL) {
fprintf(stderr, "Error: could not open file '%s'\n", argv[1]);
exit(EXIT_FAILURE);
}
else{
printf("File %s opened!\n", argv[1]);
}
}
read_file_to_buffer(file);
string_check(buffer);
fclose(file);
free(buffer);
buffer = NULL;
exit(EXIT_SUCCESS);
}
void read_file_to_buffer(FILE *file) {
long file_size = 0;
if(buffer != NULL){
fprintf(stderr, "buffer in use\n");
exit(EXIT_FAILURE);
}
rewind(file);
if (fseek(file, 0, SEEK_END) != 0){
perror("Could not seek to end of file");
exit(EXIT_FAILURE);
}
file_size = ftell(file);
if (file_size < 0){
perror("could not tell size of file");
exit(EXIT_FAILURE);
}
rewind(file);
buffer = (char *)malloc(sizeof(char) * (file_size + 1));
if (buffer == NULL){
fprintf(stderr, "Could not allocate memory");
exit(EXIT_FAILURE);
}
if(fread(buffer, sizeof(char), (size_t)file_size, file) != file_size){
fprintf(stderr, "Could not read file\n");
exit(EXIT_FAILURE);
}
buffer[file_size] = '\0';
return;
}
void string_check(char *buffer){
int i = 0;
int j = 0;
char base_in[2];
char number[50];
char base_out[2];
int actual_number[100];
int end_number = 0;
int x = 0;
int y = 0;
int in_base;
int out_base;
while( buffer[i] != '\0'){
if (buffer[i] != '#' && buffer[i] != ' ' && buffer[i] != '\n' && buffer[i] != '\r'){
while (buffer[i] != ' '){
base_in[j] = buffer[i];
i++;
j++;
}
j = 0;
i++;
if (base_in[1] != '\0'){
x = char_to_int(base_in[0]);
y = char_to_int(base_in[1]);
in_base = int_conversion(x, y);
x = 0;
y = 0;
}
else{
in_base = char_to_int(base_in[0]);
}
while (buffer[i] != ' '){
number[j] = buffer[i];
i++;
j++;
}
int q;
q=j;
j=0;
while (number[j] != '\0'){
actual_number[j] = char_to_int(number[j]);
end_number = end_number + pow(in_base, q-1) * actual_number[j];
j++;
q--;
}
j = 0;
i++;
while (buffer[i] != '\n' && buffer[i] != '\0'){
base_out[j] = buffer[i];
i++;
j++;
}
if (base_out[1] != '\0'){
x = char_to_int(base_out[0]);
y = char_to_int(base_out[1]);
out_base = int_conversion(x, y);
x = 0;
y = 0;
}
else{
out_base = char_to_int(base_out[0]);
}
j = 0;
i++;
base_conversion(end_number, out_base);
}
else{
while (buffer[i] != '\n' && buffer[i] != '\0'){
i++;
}
}
i++;
}
return;
}
int char_to_int(char c){
char map[] = "0123456789abcdefghijklmnopqrstuvwxyz";
int result = -1;
char *next = map;
while(*next != '\0'){
if(*next == c){
result = next - map;
break;
}
next++;
}
return result;
}
int int_conversion(int x, int y){
int value;
value = (x * 10) + y;
return value;
}
void base_conversion(int end_number, int out_base){
int remainder[100];
char map[] = "0123456789abcdefghijklmnopqrstuvwxyz";
int index = 0;
int i;
while (end_number != 0){
remainder[index] = end_number % out_base;
end_number = end_number / out_base;
index++;
}
for (i=0; i<index; i++){
printf("%c", map[remainder[index-1]]);
}
printf("\n");
return;
}
OP's base_conversion() is messed.
Loop prints same character repeatedly.
for (i=0; i<index; i++){
printf("%c", map[remainder[index-1]]); // Why same character?
}
Code is using signed math and % and can create negative remainders which may be used as array index.
remainder[index] = end_number % out_base; // result may be negative.
...
printf("%c", map[remainder[index-1]]); // accessing out of bounds with negative
Suggested simplification.
void base_conversion_helper(unsigned end_number, int out_base){
if (end_number >= out_base) base_conversion_helper(end_number/out_base, out_base);
putchar("0123456789abcdefghijklmnopqrstuvwxyz"[end_number % outbase]);
}
void base_conversion(unsigned end_number, int out_base){
assert(out_base >= 2 && out_base <= 36);
base_conversion_helper(end_number, out_base);
putchar('\n');
}

Multiline CSV file to matrix in C

I'm writing program to count scores.
The input file full list.txt looks like:
123456,11,24,,51,,12,,76,,,531,12,,,,24,56,,,,,118,,,,,,,,,,,,,,20,,,,,
123456,11,24,,51,,12,,76,,,531,12,,,,24,56,,,,,118,,,,,,,,,,,,,,20,,,,,
123456,11,24,,51,,12,,76,,,531,12,,,,24,56,,,,,118,,,,,,,,,,,,,,20,,,,,
123456,11,24,,51,,12,,76,,,531,12,,,,24,56,,,,,118,,,,,,,,,,,,,,20,,,,,
...
123456,11,24,,51,,12,,76,,,531,12,,,,24,56,,,,,118,,,,,,,,,,,,,,20,,,,,
The first number is ID, rest are scores. I was trying to put this file to matrix of c[42][1000] to count the total scores and arrange them in increasing order... But the problem I've faced is:
The program only counts the 1st line so far....
Any ideas how to make it store all of them?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int lines_allocated = 1000;
int max_line_len = 150;
double c[42][1000];
char **words = (char **)malloc(sizeof(char*)*lines_allocated);
if (words==NULL)
{
fprintf(stderr,"Out of memory (1).\n");
exit(1);
}
FILE *fp = fopen("full list.txt", "r");
if (fp == NULL)
{
fprintf(stderr,"Error opening file.\n");
exit(2);
}
int i;
for (i=0;1;i++)
{
int j;
if (i >= lines_allocated)
{
int new_size;
new_size = lines_allocated*2;
words = (char **)realloc(words,sizeof(char*)*new_size);
if (words==NULL)
{
fprintf(stderr,"Out of memory.\n");
exit(3);
}
lines_allocated = new_size;
}
words[i] = (char*)malloc(max_line_len);
if (words[i]==NULL)
{
fprintf(stderr,"Out of memory (3).\n");
exit(4);
}
if (fgets(words[i],max_line_len-1,fp)==NULL)
break;
for (j=strlen(words[i])-1;j>=0 && (words[i][j]=='\n' || words[i][j]=='\r');j--)
;
words[i][j]='\0';
}
int j;
int k=i;
for(j = 0; j < k; j++)
{
printf("%s\n", words[j]);
char *pptr = words[j];
int l;
words[j][strlen(words)-1]=',';
for (l = 0; l < 41; l++)
{
char *ptr = strchr(pptr, ',');
if (ptr)
{
*ptr = 0;
c[l][j] = atof(pptr);
pptr = ptr + 1;
}
}
for (l = 0; l < 41; l++)
{
printf("%.2lf\n", c[l][j]);
}
return 0;
}
for (;i>=0;i--)
free(words[i]);
free(words);
return 0;
}
May be the matrix doesn't store any value at all.
BLUEPIXY, thanks for attention, solved =)
Was extra return 0.
However:
words[j][strlen(words)-1]=',';
or
words[j][strlen(words[j])-1]=',';
Does not affect the matrix. I have no idea why it does not, but it should, shouldn't it?
Final code is following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
int lines_allocated = 1000;
int max_line_len = 150;
double c[42][1000];
char **words = (char **)malloc(sizeof(char*)*lines_allocated);
if (words==NULL)
{
fprintf(stderr,"Out of memory (1).\n");
exit(1);
}
FILE *fp = fopen("full list.txt", "r");
if (fp == NULL)
{
fprintf(stderr,"Error opening file.\n");
exit(2);
}
int i;
for (i=0;1;i++)
{
int j;
if (i >= lines_allocated)
{
int new_size;
new_size = lines_allocated*2;
words = (char **)realloc(words,sizeof(char*)*new_size);
if (words==NULL)
{
fprintf(stderr,"Out of memory.\n");
exit(3);
}
lines_allocated = new_size;
}
words[i] = (char*)malloc(max_line_len);
if (words[i]==NULL)
{
fprintf(stderr,"Out of memory (3).\n");
exit(4);
}
if (fgets(words[i],max_line_len-1,fp)==NULL)
break;
for (j=strlen(words[i])-1;j>=0 && (words[i][j]=='\n' || words[i][j]=='\r');j--)
;
words[i][j]='\0';
}
int j;
int k=i;
for(j = 0; j < k; j++)
{
printf("%s\n", words[j]);
char *pptr = words[j];
int l;
words[j][strlen(words)-1]=',';
for (l = 0; l < 42; l++)
{
char *ptr = strchr(pptr, ',');
if (ptr)
{
*ptr = 0;
c[l][j] = atof(pptr);
pptr = ptr + 1;
}
}
}
int l;
for (j = 0; j < k; j++)
{
printf("\n");
for (l = 0; l < 42; l++)
{
printf("%.2lf\t", c[l][j]);
}
}
for (;i>=0;i--)
free(words[i]);
free(words);
return 0;
}
However, now the problem is the value after last comma does not included to array....

Resources