Writing to char* array in C throws segfault - c

I'm an infosec student, who has just begun learning C. I've been given an assignment to write a simple translation program using this prototype: char* dictionary[number_of_words][2];.
The output should look something like this:
Enter # of words to add: 3
dictionary[0][0]= plane
dictionary[0][1]= Flugzeug
dictionary[1][0]= house
dictionary[1][1]= Haus
dictionary[2][0]= cat
dictionary[2][1]= Katze
Enter english word to translate: house
---> Haus
My current (work in progress) code looks like this:
void clean_stdin(void);
int main(void)
{
unsigned int i = 0,j = 0,size;
printf("Enter # of words to add: ");
scanf("%u",&size);
clean_stdin(); //clears input buffer
char* dictionary[size][2];
while(i <= size)
{
printf("dictionary[%u][%u]= ",i,j);
fgets(dictionary[i][j],100,stdin);
if(j >= 1)
{
j = 0;
++i;
}
else
j = 1;
}
return 0;
}
The code throws no errors when compiled with gcc -Wall main.c, but this is the behaviour I get:
Enter # of words to add: 3
dictionary[0][0]= plane
dictionary[0][1]= Flugzeug
dictionary[1][0]= house
dictionary[1][1]= Haus
fish: “./a.out” terminated by signal SIGSEGV (Adressbereichsfehler)
*****
Enter # of words to add: 4
dictionary[0][0]= plane
fish: “./a.out” terminated by signal SIGSEGV (Adressbereichsfehler)
There's a fundamental flaw somewhere in my thought process. Any help/heads up is very appreciated. Cheers!

Let's look at this part of your code:
char* dictionary[size][2];
while(i <= size)
{
printf("dictionary[%u][%u]= ",i,j);
fgets(dictionary[i][j],100,stdin);
Each dictionary[i][j] is a pointer to char, but you haven't set them to point anywhere meaningful yet - each array element contains some random bit pattern that may or may not correspond to a writable address. Your first few entries get written somewhere, but eventually you try to write to a memory location you don't own or don't have access to.
You will need to set aside additional memory to store each individual string. You either need create a 3D array of char (not char *):
#define MAX_STR_LEN 100
...
char dictionary[size][2][MAX_STR_LEN+1];
or you will need to dynamically allocate memory for each array entry:
while ( i < size ) // <, not <=
{
dictionary[i][j] = malloc( sizeof *dictionary[i][j] * (MAX_STR_LEN + 1));
if ( !dictionary[i][j] )
{
// memory allocation failed, handle error
}
printf("dictionary[%u][%u]= ",i,j);
fgets(dictionary[i][j],MAX_STR_LEN,stdin);
If you allocate memory dynamically, you will need to explicitly free it when you're done:
for ( i = 0; i < size; i++ )
{
free( dictionary[i][0] );
free( dictionary[i][1] );
}

instead of messing around with arrays of multiple dimensions, I suggest you use structures:
#include <stdio.h>
#include <string.h>
int main()
{
unsigned int size;
printf("Enter # of words to add: ");
if (scanf("%u", &size) != 1)
return 1; // cannot convert input to integer
#define WORD_MAX_SIZE 100
struct {
char word[WORD_MAX_SIZE];
char translation[WORD_MAX_SIZE];
} dictionary[size];
memset(dictionary, 0, sizeof(dictionary));
for (int i = 0; i < size; i++) {
printf("dictionary[%u].word= ", i);
fgets(dictionary[i].word, WORD_MAX_SIZE, stdin);
printf("dictionary[%u].translation= ", i);
fgets(dictionary[i].translation, WORD_MAX_SIZE, stdin);
}
// do something with your stuff
}

fgets(dictionary[i][j],100,stdin); reads from an uninitialized variable (dictionary[i][j] was never given a value), which has undefined behavior.
Also, i is going out of bounds later.

Related

How can I arrange the structs in an array of structs in an ascending order?

I am sorry if this sounds confusing, I will try to be as clear as possible. I have an array of structs, where the array stores a struct that I have defined as a Business Card. However, before adding any new business cards into the array, I have to store the structs in ascending order based on the integer value of the Employee ID.
Here is the struct:
typedef struct{
int nameCardID;
char personName[20];
char companyName[20];
} NameCard;
Hence, I tried to use relational operators to compare between the values of the ID and copy it in ascending order to another temporary array I named fakeHolder, before finally copying over to the actual array. However, I can't seem to understand why it is not in order after inputting my data as ID 9, 7, 5.
Here is my helper function:
int addNameCard(NameCard *nc, int *size){
int i = 0;
// Why is this a pointer?
NameCard fakeHolder[10];
char dummy[100];
char *p;
printf("addNameCard():\n");
if(*size == MAX){
printf("The name card holder is full");
// To quit the program
return 0;
}
// Keeps it to Fake Name Card Holder First
printf("Enter nameCardID:\n");
scanf("%d", &fakeHolder->nameCardID);
scanf("%c", &dummy);
printf("Enter personName:\n");
fgets(fakeHolder->personName, 20, stdin);
if(p = strchr(fakeHolder->personName, '\n')){
*p = '\0';
}
printf("Enter companyName:\n");
fgets(fakeHolder->companyName, 20, stdin);
if(p = strchr(fakeHolder->companyName, '\n')){
*p = '\0';
}
// Compare the ID value
for(int j = 0; j < *size; j += 1){
if(fakeHolder->nameCardID == (nc+j)->nameCardID){
printf("The nameCardID has already existed");
}
else if(fakeHolder->nameCardID < (nc+j)->nameCardID){
fakeHolder[(j+1)].nameCardID = (nc+j)->nameCardID;
strcpy(fakeHolder[(j+1)].personName,(nc+j)->personName);
strcpy(fakeHolder[(j+1)].companyName, (nc+j)->companyName);
}
}
*size += 1;
// Transfer to the Actual Name Card Holder
for(int k = 0; k < *size; k += 1){
(nc+k)->nameCardID = fakeHolder[k].nameCardID;
strcpy((nc+k)->personName, fakeHolder[k].personName);
strcpy((nc+k)->companyName, fakeHolder[k].companyName);
}
printf("The name card has been added successfully\n");
return 0;
}
Your current code has several problems, and you can rewrite it to be much more maintainable and easier to work with. For example,
i (in int i = 0;) is not being used
scanf("%c", &dummy); is there, I assume, to remove trailing \n - but a 100-char buffer for a single character to read is... surprising. See scanf() leaves the new line char in the buffer for lots of discussion on different approaches to "trailing stuff after integer".
splitting addNameCard into 2 functions, one to actually request a NameCard and another to insert it into the array, would divide up responsibilities better, and make your program easier to test. Avoid mixing input/output with program logic.
The question you ask can be solved via the standard library qsort function, as follows:
#include <stdlib.h>
typedef struct{
int nameCardID;
char personName[20];
char companyName[20];
} NameCard;
void show(NameCard *nc, int n) {
for (int i=0; i<n; i++, nc++) {
printf("%d,%s,%s\n",
nc->nameCardID, nc->personName, nc->companyName);
}
}
// comparison functions to qsort must return int and receive 2 const void * pointers
// they must then return 0 for equal, or <0 / >0 for lower/greater
int compareCardsById(const void *a, const void *b) {
return ((NameCard *)a)->nameCardID - ((NameCard *)b)->nameCardID;
}
int main() {
NameCard nc[10];
nc[0] = (NameCard){1, "bill", "foo"};
nc[1] = (NameCard){3, "joe", "bar"};
nc[2] = (NameCard){2, "ben", "qux"};
show(nc, 3);
// calling the libraries' sort on the array; see "man qsort" for details
qsort(nc, 3, sizeof(NameCard), compareCardsById);
show(nc, 3);
return 0;
}

HEAP CORRUPTION DETECTED: after normal block(#87)

I'm trying to do a program that get number of names from the user, then it get the names from the user and save them in array in strings. After it, it sort the names in the array by abc and then print the names ordered. The program work good, but the problem is when I try to free the dynamic memory I defined.
Here is the code:
#include <stdio.h>
#include <string.h>
#define STR_LEN 51
void myFgets(char str[], int n);
void sortString(char** arr, int numberOfStrings);
int main(void)
{
int i = 0, numberOfFriends = 0, sizeOfMemory = 0;
char name[STR_LEN] = { 0 };
char** arrOfNames = (char*)malloc(sizeof(int) * sizeOfMemory);
printf("Enter number of friends: ");
scanf("%d", &numberOfFriends);
getchar();
for (i = 0; i < numberOfFriends; i++) // In this loop we save the names into the array.
{
printf("Enter name of friend %d: ", i + 1);
myFgets(name, STR_LEN); // Get the name from the user.
sizeOfMemory += 1;
arrOfNames = (char*)realloc(arrOfNames, sizeof(int) * sizeOfMemory); // Change the size of the memory to more place to pointer from the last time.
arrOfNames[i] = (char*)malloc(sizeof(char) * strlen(name) + 1); // Set dynamic size to the name.
*(arrOfNames[i]) = '\0'; // We remove the string in the currnet name.
strncat(arrOfNames[i], name, strlen(name) + 1); // Then, we save the name of the user into the string.
}
sortString(arrOfNames, numberOfFriends); // We use this function to sort the array.
for (i = 0; i < numberOfFriends; i++)
{
printf("Friend %d: %s\n", i + 1, arrOfNames[i]);
}
for (i = 0; i < numberOfFriends; i++)
{
free(arrOfNames[i]);
}
free(arrOfNames);
getchar();
return 0;
}
/*
Function will perform the fgets command and also remove the newline
that might be at the end of the string - a known issue with fgets.
input: the buffer to read into, the number of chars to read
*/
void myFgets(char str[], int n)
{
fgets(str, n, stdin);
str[strcspn(str, "\n")] = 0;
}
/*In this function we get array of strings and sort the array by abc.
Input: The array and the long.
Output: None*/
void sortString(char** arr, int numberOfStrings)
{
int i = 0, x = 0;
char tmp[STR_LEN] = { 0 };
for (i = 0; i < numberOfStrings; i++) // In this loop we run on all the indexes of the array. From the first string to the last.
{
for (x = i + 1; x < numberOfStrings; x++) // In this loop we run on the next indexes and check if is there smaller string than the currnet.
{
if (strcmp(arr[i], arr[x]) > 0) // If the original string is bigger than the currnet string.
{
strncat(tmp, arr[i], strlen(arr[i])); // Save the original string to temp string.
// Switch between the orginal to the smaller string.
arr[i][0] = '\0';
strncat(arr[i], arr[x], strlen(arr[x]));
arr[x][0] = '\0';
strncat(arr[x], tmp, strlen(tmp));
tmp[0] = '\0';
}
}
}
}
After the print of the names, when I want to free the names and the array, in the first try to free, I get an error of: "HEAP CORRUPTION DETECTED: after normal block(#87)". By the way, I get this error only when I enter 4 or more players. If I enter 3 or less players, the program work properly.
Why does that happen and what I should do to fix it?
First of all remove the unnecessary (and partly wrong) casts of the return value of malloc and realloc. In other words: replace (char*)malloc(... with malloc(..., and the same for realloc.
Then there is a big problem here: realloc(arrOfNames, sizeof(int) * sizeOfMemory) : you want to allocate an array of pointers not an array of int and the size of a pointer may or may not be the same as the size of an int. You need sizeof(char**) or rather the less error prone sizeof(*arrOfNames) here.
Furthermore this in too convoluted (but not actually wrong):
*(arrOfNames[i]) = '\0';
strncat(arrOfNames[i], name, strlen(name) + 1);
instead you can simply use this:
strcpy(arrOfNames[i], name);
Same thing in the sort function.
Keep your code simple.
But actually there are more problems in your sort function. You naively swap the contents of the strings (which by the way is inefficient), but the real problem is that if you copy a longer string, say "Walter" into a shorter one, say "Joe", you'll write beyond the end of the allocated memory for "Joe".
Instead of swapping the content of the strings just swap the pointers.
I suggest you take a pencil and a piece of paper and draw the pointers and the memory they point to.

character missing on using Realloc and strcat on multidimensional array?

helloeveryone. I am fairly new to programming and currently trying to learn C programming to advance further in any of my projects. I've just learned how to use malloc and realloc, and all seemed good until I attempted to use strcat to combine two given strings from multidimensional array.
I am supposed to get combination of two strings based on the user inputs, and strangely, the first character is either missing or replaced by other characters...
I'll include the source code as well as the output below. I'd really appreciate you help. Thanks in advance!! ( don't mind the Korean at the end... I am korean :P)
enter code here
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main(void)
{
int i, j;
const int row = 3;
char *pstr[3];
char temp[100];
int k,p = 0;
printf("Type in any three characters\n");
for (i = 0; i < row; i++)
{
pstr[i] = (char *)malloc(strlen(temp) + 1); //initialize the lenght of the elements in 2 part of 2D array of char b[ROW] via length of the given string
}
for (i = 0; i < row; i++)
{
scanf("%s", temp);
strcpy(pstr[i], temp);
}
printf("\n");
for (i = 0; i < row; i++)
{
printf("%s\n", pstr[i]);
}
scanf("%d", &p);
scanf("%d", &k);
printf("%s\n", pstr[p]);
printf("%s\n", pstr[k]);
*pstr[k] = (char *)realloc(pstr[k], strlen(pstr[p])+100);
strcat(pstr[k], pstr[p]);
printf("%s", pstr[k]);
for (i = 0; i < row; i++)
{
free(pstr[i]);
}
return 0;
}
\
output::LINK IS AN INTERNATIONAL SIGN FOR , IMAGE OVER HERE!!!
Two major problems:
You use temp before it have been initialized, when its contents is indeterminate and that will lead to undefined behavior.
When you do *pstr[k] = realloc(...) you dereference the pointer in pstr[k] and gets it's first element, which is a single character. You then assign the result of the realloc call to this char element. So you basically lose the actual pointer and pstr[k] will still point to the same memory (which might now be invalid).
There are other problems, but these two are the worst.
I found these in your code
1) if k or p is greater than 2 it will give runtime error
2) *pstr[k] = (char *)realloc(pstr[k], strlen(pstr[p])+100);
but this line can give error in compile time also(mac at least) - as they are not same
so you may change like this -
*pstr[k] = *(char *)realloc(pstr[k], strlen(pstr[p])+100);
3) After realloc you will get exception in free. see this - How free memory after of realloc

Load numbers from input into array

I have given input which contains data that I am going to process and saved into an array. The input looks like this :
{ [1, 10], [2,1] , [-10, 20] }
it can have more elements in it. I need to process it that I can load all numbers from [ number , number ] into 2d array , first number should be at 0th and second number should be at 1st index so this array should look like
[[1,10],[2,1],[-10,20]]
But I've failed to find the solution, how to process this input into my desired array. What is the right way to do it?
I tried to do as following:
int main()
{
long long int cisla[10][2];
int x;
int y;
int i;
int index=0;
int counter=0;
char c;
char zatvorka_one;
char zatvorka_three;
char ciarka;
char ciarka_two;
printf("Pozicia nepriatela\n");
c=getchar();
if(c!='{'){
return 0;
}
scanf(" %c%d,%d%c",&ciarka,&x,&y,&zatvorka_one);
cisla[index][0]=x;
cisla[index][1]=y;
index++;
while(1){
scanf("%c",&ciarka);
if(ciarka=='}'){
break;
}
scanf(" %c%d%,%d%c",&ciarka,&x,&y,&zatvorka_one);
cisla[index][0]=x;
cisla[index][1]=y;
index++;
}
for ( i = 0; i < index; i++){
printf("%d %d\n",cisla[i][0],cisla[i][1]);
}
}
But somehow it returns unexpected result, how can i fix it?
You should use gets instead of scanf. gets will return the entire string wich will be easear. Then you ahould read about strtok wich can be used to separate a string. For example: strtok(s,",") will separate your string into smaller strings. For the input {[12,4], [8,9]} will divide into: first string: {[12 second string: 4] third string [8 and fourth string 9]}. Now you will just have to remove the characters that are not numbers like { } and []. After that you will have strings only with the numbers so you can use another predefined fuction you should read abput called atoi. It recieves a string and turns it into an int (ascci to int). There is also an atof (ascci to float) if you need it. Tuturialpoints is a good place to look for examples on how to use these functions i mentioned.
I'm relatively new to C and SO. Maybe I shouldn't give you the solution, but I did. It follows the advice of sharp c student.
You could try to do it like this:
#include "stdafx.h"
#include "string.h"
#include "stdlib.h"
#define MAXNBRELM 10 // maximum number of elements; adjust as needed
int main()
{
int IntArr[MAXNBRELM][2]; // integer array to hold results
int s = 0; // subscript
int NbrElm; // number of elements found
char Buf[81]; // buffer to hold input
char * StrPtr; // pointer to string for fgets
char * TknChr; // each individual token
char * NxtTkn; // next token position (only needed for Visual C++)
StrPtr = fgets(Buf, 80, stdin);
TknChr = strtok_s(Buf, " {[,]}", &NxtTkn);
while (s <= MAXNBRELM && TknChr != NULL) {
IntArr[s][0] = atoi(TknChr);
TknChr = strtok_s(NULL, " {[,]}", &NxtTkn);
if (TknChr != NULL) {
IntArr[s][1] = atoi(TknChr);
TknChr = strtok_s(NULL, " {[,]}", &NxtTkn);
s++;
}
}
NbrElm = s;
for (s = 0; s < NbrElm; s++)
printf("%d %d\n", IntArr[s][0], IntArr[s][1]);
return 0;
}
This is for Visual Studio, is why I needed to use strtok_s and &NxtTkn.

Fill dynamically sized array in C++ and use the values

I'd like to fill a char-array dynamically and check whether the contained values are valid integers, here's what I got so far:
for(int i = 0; i < 50000; i++)
{
if(input[i] == ',')
{
commaIndex = i;
}
}
commaIndex is the index of a comma inside a file, numerical values should have been entered before a comma, file looks like this: -44,5,19,-3,13,(etc), it's important for this part:
char *tempNumber = new char[commaIndex];
Fill tempNumber (which should presumably be just as big as the number due to my dynamic allocation) so I don't have a number in a size 50000 char-array (named input).
for(int i = 0; i < commaIndex; i++)
{
cout << i << "\n";
tempNumber[i] = input[i];
}
And now I want to use it:
if(!isValidInteger(tempNumber))
{
cout << "ERROR!\n";
}
Unfortunately, tempNumber always seems to be of size 4 irregardless of the value of "commaIndex", i.e. I get the following output:
(Inputdata: 50000,3,-4)
commaIndex: 5
content of tempNumber: 5000 (one 0 missing)
commaIndex: 1
content of tempNumber: 3²²² (notice the 3 ^2s)
commaIndex: 2
content of tempNumber: -4²²
Any ideas?
One more thing: This is for a homework assignment and I am not allowed to use any object-oriented element of C++ (this includes strings and vectors, I've been there and I know it would be SO easy.)
Thanks,
Dennis
You might be interested by the strtol function.
You may also consider using strtok() with sscanf(). Notice, that strtol() does not allow you to check for errors since it simply returns (perfectly valid) value 0 on parse error. On the other hand, sscanf() returns number of successfully read items, so you may easily check if there was an error while reading a number.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i = 0;
char str[] = "1,2,-3,+4,a6,6";
/* calculate result table size and alloc */
int max = 1;
char* tmp = str;
while (*tmp)
if (*tmp++ == ',')
++max;
int* nums = malloc(sizeof(int) * max);
/* tokenize string by , and extract numbers */
char* pch = strtok(str, ",");
while (pch != NULL) {
if (sscanf(pch, "%d", &nums[i++]) == 0)
printf("Not a number: %s\n", pch);
pch = strtok(NULL, ",");
}
/* print read numbers */
for (i = 0; i < max; ++i)
printf("%d\n", nums[i]);
free(nums);
return 0;
}

Resources