Function to search for string in array of strings - c

I am trying to write a function that searches for the unique part(maximum two characters) of a string in an array of strings. Although strstr and strchr are not working and crash my program for some reason. So I have resorted to trying to create something that resembles their function.
My question is this:
Why is strstr not working (something like strstr(lex[j],word)) and what am I doing wrong here?
Here is the code for the function that searches for two unique characters within an array of strings :
void convert(char word[])
{
int i;
for (i = 0 ; i <= strlen(word) ; i++)
{
if(word[i] >= 65 && word[i] <= 90)
{
word[i] = word[i]+32;
}
}
}
int twochar(char lex[50][50],char word[], int size,char temp[3])
{
int i,j,k,count,totlen;
convert(word);
for (i = 0 ; i < strlen(word) - 1 ; i++)
{
count = 0;
totlen = 0;
for(j = 0; j<size; j++)
{
convert(lex[j]);
totlen += strlen(lex[j]) - 1;
for(k = 0 ; k < strlen(lex[j]) - 1 ; k++)
{
if (word[i] != lex[j][k] || word[i+1] != lex[j][k + 1])
{
count++;
}
}
}
if(count = = totlen)
{
temp[0] = word[i];
temp[1] = word[i+1];
}
}
}
int main(int argc, char *argv[])
{
char lex[50][50] = {"word1","word2","word3","word4" }, word[] = "test";
char p[3];
twochar(lex,word,4,p);
printf("%c%c\n",p[0],p[1]);
return 0;
}

this line:
for(k=0;k<strlen(lex[j])-1;k++)
is the problem.
strlen(lex[0]) is 0
strlen(lex[0])-1 is -1 (0xFFFFFFFF in a 32 bit system)
k starts at 0 and is incremented until it is equal to 0xFFFFFFFF
of course, k exceeds the bounds of lex[0] when k = 50.
the result is undefined behaviour which leads to the seg fault event
To determine all the above, I compiled/linked the program via gcc, with the -ggdb parameter.
then I ran the program via 'gdb theprogram'
within gdb I entered
br main <-- break point set
run
c <-- continue
the program then crashed with a seg fault event
then I entered
bt <-- back trace
the bt showed me this line: 'if(word[i]!=lex[j][k] || word[i+1]!=lex[j] [k+1])'
Then I entered
p k <-- print variable k
=6832 (which is WAY out of bounds)
then I entered
run
y
br theprogram.c:41 (the line number from above) <-- set another break epoint
c
the program stopped at line 41
p j
=0 ( this was the gdb response )
p k
= 0
p i
= 0
a little thinking,
stepping though that inner loop using 'n' <-- next
and playing on gdb
indicated that the problem was in line 42
and resulted in revealing the root of the problem

Related

Why I am getting a space character in my program in the place of third last character?

Why I am getting a space character in my program in the place of third last character?
Even if I change the string str variable I get the same result.
#include <stdio.h>
#include <string.h>
void parser(char array[])
{
int a, b;
for (int i = 0; i < strlen(array); i++) {
if (array[i] == '>') {
a = i;
break;
}
}
for (int j = a; j < strlen(array); j++) {
if (array[j] == '<') {
b = j;
}
}
for (int p = 0, q = a + 1; p < b - a - 1, q < b; p++, q++) {
array[p] = array[q];
array[b - a] = '\0';
printf("%c", array[p]);
}
}
int main()
{
char str[] = "<h1>hello there i am programmer.</h1>";
parser(str);
return 0;
}
There are many things that could be written better in the code but they do not affect the result.
The line that produces the unexpected outcome is:
array[b-a]='\0';
When this for loop starts...
for(int p=0,q=a+1;p<b-a-1,q<b;p++,q++){
array[p]=array[q];
array[b-a]='\0';
printf("%c",array[p]);
}
... the values of a and b are 3 and 32.
The statement array[b-a]='\0'; puts the NUL terminator character at position 29 in array.
The loop starts with p=0, q=4 (a+1) and repeats until p reaches 28 and q reaches 31 (q<b)*.
When p is 25, q is 29 and array[29] has been repeatedly set to '\0' on the previous iterations, therefore '\0' is copied at position 25 and printed on screen.
You should set the NUL terminator only once, after the loop. And the right position for it is b-a-1, not b-a; you expressed this correctly in the for initialization (p=0) and exit condition (p<b-a-1).
All in all, the code around the last for loop should be like this:
for(int p=0, q=a+1;q<b;p++,q++){
array[p]=array[q];
printf("%c",array[p]);
}
array[b-a-1]='\0';
*The condition p<b-a-1 is ignore because of the comma character. You probably want & between the conditions but they are equivalent, one of them is enough.

converting binary to multiple characters

I basically posted this question yesterday, but I'm running into a different type of error. So I'm trying to create a program where the user enters a 12-bit binary hamming code sequence like "100010010001" and it should print out its corresponding ASCII character, which in this case is 'A'.
The problem is it seems to work for single characters like 'A' but if I type the binary sequence 100010010001010110010010010010000011 which represents 'ABC' it prints out random characters unrelated to what should be printed out. I don't understand what's causing this problem?
char charToBin(char usersInput[]) {
char j = 0 ;
for (int i = 0; i <= 12 ; i++) {
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
continue ;
} ;
usersInput[j] = usersInput[i] ;
j++ ;
} ;
char c = strtol(usersInput, (char **)NULL, 2);
return c;
}
You should try my answer to that question of your yesterday. That solution will work and the first method should be really fast if you trying to break up the array into steps because it is a small array.
Nonetheless, for this code, the main problem that you have with your code is that you are trying to remove 4 indexes from a char array of 12 indexes without doing anything to tell strtol() that. So in your code, you only have to tell strtol() to stop at index 8 by injecting char '\0' at position 8 or the array which would be the 9th char. Also, since you are going to skip index 0 and 1, there is no point starting from index 0 and evaluating whether if it is index 0 or 1. You can start at index 2. Besides that, "i" should be less than 12 in your loop. That is because the last index of a 12 indexes array would be 11, and not 12. Also, j does not need to be a char. That should be an int.
char charToBin(char usersInput[]) {
int j = 0 ;
for (int i = 2; i < 12 ; i++) {
if( (i == 3) || (i == 7) ){
continue ;
} ;
usersInput[j] = usersInput[i] ;
j++ ;
} ;
usersInput[8] = '\0';
char c = strtol(usersInput, (char **)NULL, 2);
return c;
}
You must provide more info about your program like fully functional main(), example input and outputs, how to call the functions and etc.
But before that i think Same code like this may works for you.
p = len of usersInput / 12
char * charToBin(char usersInput[], int p) {
char j = 0 ;
char *c;
for(int n=0;n<p;n++){
for (int i = 0; i <= 12 ; i++) {
if((i == 0) || (i == 1) || (i == 3) || (i == 7)){
continue ;
} ;
usersInput[j+n] = usersInput[i+n] ;
j++ ;
} ;
c[n] = strtol(usersInput, (char **)NULL, 2);
}
return c;
}
Your for() loop should only iterate for 12 times,hence the condition should be i<12 and create a local character array as I did(to_Char[]) of length 9(8+1 for Null at end) and read appropriate bits into it from usersInput[], usersInput[] shouldn't be provided as input to strtol() as its of 32bits in length but our characters are just 8bits in length.
char charToBin(char usersInput[]) {
char j = 0;
char to_Char[9];
for (int i = 0; i < 12; i++) {
if ((i == 0) || (i == 1) || (i == 3) || (i == 7)) {
continue;
};
to_Char[j] = usersInput[i];
j++;
};
to_Char[j] = '\0';
char c = strtol(to_Char, (char**)NULL, 2);
return c;
}

Nested for loop isn't iterating

I'm trying a K and R exercise. The program is to compare two strings. If the first string has any characters that are also in string 2 then it will be deleted in string1.
The goal of my compare function below is to compare every array element in the first string with every array element in the second string. If we've got a match then we "raise a red flag" (acting as a boolean value) and we DON'T add it to the new array that will contain the edited string1. However it seems to be ignoring the second for loop. It only passes through on the k = 0 iteration for every i iteration. My other issue is that based on the output (provided beneath node) it seems that s1[i] is being assigned to s2[k]. I'm guessing this takes place in the if statement but how would that be possible? Any help anyone could provide would be very appreciated.
I used the GNU GCC compiler if it makes a difference.
#include <stdio.h>
int getLength(char s[]);
char compare(char s1[], char s2[],int s1Length, int s2Length);
int main()
{
char stringOne[] = {'a','b','c','d','e'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z'};
int lengthOne;
int lengthTwo;
lengthOne = getLength(stringOne);
char theResultingString[lengthOne];
lengthTwo = getLength(stringTwo);
compare(stringOne, stringTwo, lengthOne, lengthTwo);
return 0;
} //end of main.
int getLength(char s[]) //getLength gives us the length of each and every string
{
int i=0;
for(i = 0; s[i]!='\0'; i++) {
} //end for loop
return i;
} //end of getLength
char compare(char s1[], char s2[],int s1Length, int s2Length)
{
int redFlagRaised = 0; //This will be used as a boolean indicator if we have a matching element
char toBeReturned[s1Length];
int i;
int k;
for(i = 0; i<s1Length; i++) {
printf("i is now %d\n",i);
for(k = 0; k<s2Length; k++) {
printf("k is now %d\n",k);
if(s1[i] = s2[k]) { //If at any point the s1 char being examined equals any of s2 chars then
printf("s1[i] is %c\n",s1[i]);
printf("s2[i] is %c\n",s2[i]);
redFlagRaised = 1; //we raise the red flag!
} //end first inner if statement
if((k=(s2Length-1))&&(redFlagRaised = 0)) { //if we reach the end and we DON'T have a red flag then
toBeReturned[i] = s1[i];
printf("toBeReturned[0] is %c\n",toBeReturned[0]);
} //end second inner if statement
} //end inner for loop
redFlagRaised = 0; //We lower the flag again for the next inner for loop iteration
} //end outer for loop
printf("The result is %c", toBeReturned[0]);
return toBeReturned[0];
} //end of compare
Output:
i is now 0
k is now 0
s1[i] is P
s2[i] is P
i is now 1
k is now 0
s1[i] is P
s2[i] is f
i is now 2
k is now 0
s1[i] is P
s2[i] is g
i is now 3
k is now 0
s1[i] is P
s2[i] is c
i is now 4
k is now 0
s1[i] is P
s2[i] is t
i is now 5
k is now 0
s1[i] is P
s2[i] is y
The result is �
Process returned 0 (0x0) execution time : 0.005 s
Press ENTER to continue.
char stringOne[] = {'a','b','c','d','e'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z'};
These are not strings. You need to terminate them using null character.
Try this -
char stringOne[] = {'a','b','c','d','e','\0'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z','\0'};
Also in this condition-
if(s1[i] = s2[k])
use == instead of =(this is assignment operator).So condition should be written as -
if(s1[i]==s2[k])
Similarly in this condition (as mentioned by Weather Vane Sir in comment)if((k=(s2Length-1))&&(redFlagRaised = 0)) use ==
if((k==(s2Length-1))&&(redFlagRaised == 0))
In compare function in IF condition you are assigning the value to K like bleow
if((k=(s2Length-1))&&(redFlagRaised = 0)){ //if we reach the end and we DON'T have a red flag then
toBeReturned[i] = s1[i];
printf("toBeReturned[0] is %c\n",toBeReturned[0]);
}
But it's needs to be like this
if((k==(s2Length-1))&&(redFlagRaised == 0)){ //if we reach the end and we DON'T have a red flag then
toBeReturned[i] = s1[i];
printf("toBeReturned[0] is %c\n",toBeReturned[0]);
}
You have to use Compare operator (==) not assignment operator(=)
In below code
char stringOne[] = {'a','b','c','d','e'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z'};
These are not strings. You need to terminate them using null character. Try this -
char stringOne[] = {'a','b','c','d','e','\0'};
char stringTwo[] = {'P','f','g','c','t','y','u','o','z','\0'};
Below also use this == operator instead of = operator
if(s1[i] = s2[k])

realloc() seems to affect already allocated memory

I am experiencing an issue where the invocation of realloc seems to modify the contents of another string, keyfile.
It's supposed to run through a null-terminated char* (keyfile), which contains just above 500 characters. The problem, however, is that the reallocation I perform in the while-loop seems to modify the contents of the keyfile.
I tried removing the dynamic reallocation with realloc and instead initialize the pointers in the for-loop with a size of 200*sizeof(int) instead. The problem remains, the keyfile string is modified during the (re)allocation of memory, and I have no idea why. I have confirmed this by printing the keyfile-string before and after both the malloc and realloc statements.
Note: The keyfile only contains the characters a-z, no digits, spaces, linebreaks or uppercase. Only a text of 26, lowercase letters.
int **getCharMap(const char *keyfile) {
char *alphabet = "abcdefghijklmnopqrstuvwxyz";
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++) {
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
}
int letter;
int count = 0;
unsigned char c = keyfile[count];
while (c != '\0') {
int arr_count = charmap[c][0];
arr_count++;
charmap[c] = realloc(charmap[c], (arr_count+1)*sizeof(int));
charmap[c][0] = arr_count;
charmap[c][arr_count] = count;
c = keyfile[++count];
}
// Just inspecting the results for debugging
printf("\nCHARMAP\n");
for (int i = 0; i < 26; i++) {
letter = (int) alphabet[i];
printf("%c: ", (char) letter);
int count = charmap[letter][0];
printf("%d", charmap[letter][0]);
if (count > 0) {
for (int j = 1; j < count+1; j++) {
printf(",%d", charmap[letter][j]);
}
}
printf("\n");
}
exit(0);
return charmap;
}
charmap[(int) alphabet[i]] = malloc(sizeof(int));
charmap[(int) alphabet[i]][0] = 0; // place a counter at index 0
You are writing beyond the end of your charmap array. So, you are invoking undefined behaviour and it's not surprising that you are seeing weird effects.
You are using the character codes as an index into the array, but they do not start at 0! They start at whatever the ASCII code for a is.
You should use alphabet[i] - 'a' as your array index.
The following piece of code is a source of troubles:
int **charmap = malloc(26*sizeof(int));
for (int i = 0; i < 26; i++)
charmap[...] = ...;
If sizeof(int) < sizeof(int*), then it will be performing illegal memory access operations.
For example, on 64-bit platforms, the case is usually sizeof(int) == 4 < 8 == sizeof(int*).
Under that scenario, by writing into charmap[13...25], you will be accessing unallocated memory.
Change this:
int **charmap = malloc(26*sizeof(int));
To this:
int **charmap = malloc(26*sizeof(int*));

C segmentation error

#include <stdio.h>
void lergab(char *gab);
void criamatriz (char **alunoresp, int *resp);
int main(){
char gab[20];
char alunoresp [100][21];
int resp[80];
//lergab(&gab);
criamatriz (&alunoresp[100][21], &resp[80]);
printf ("\n\n%d\n", alunoresp[0][0]);
printf ("%c\n", alunoresp[0][1]);
printf ("%c\n", alunoresp[0][1]);
printf ("%c\n", alunoresp[0][19]);
return 0;
}
void lergab (char *gab){
int i;
for(i=0; i<20; i++)
scanf("%c\n" , &gab[i]);
printf("%c", gab[19]);
}
void criamatriz (char **alunoresp,int *resp){
int i = 0, j;
//for (i = 0; i <= 100; i++){
scanf ("%c", &alunoresp[i][0]);
for (j = 0; j < 80; j++){
scanf ("%d", &resp[j]);
}
for (j = 0; j < 80; j=j+4){
int g = 1;
if ((resp[j] + resp[j+1] + resp[j+2] + resp[j+3]) != 1)
alunoresp[i][g] = 'e';
else if (resp[j] == 1)
alunoresp[i][g] = 'a';
else if (resp[j+1] == 1)
alunoresp[i][g] = 'b';
else if (resp[j+2] == 1)
alunoresp[i][g] = 'c';
else if (resp[j+3] == 1)
alunoresp[i][g] = 'd';
g++;
}
//}
}
This code is supposed to read a number as ASCII code, then read 80 numbers and convert them to their respective character, like a electronic test scanner.
I.E:
0
0
1
0
is c,
1
0
0
0
is a,
1
0
1
0
is an invalid option (for you should only sign one answer per question).
Code is just a test, my objective here is create a matrix that contains 100 candidates with 20 answer in each of them, along with their identification code, which is the first number read as ASCII, thus alunoresp[100][21] is declared.
I'm getting segmentation error every time i try to run it on gcc, any ideas?
Edit:
Thanks for the help on the indices thing. I didn't notice.
Stil, even after fixing that i keep getting segmentation faults.
Code now looks like this:
#include <stdio.h>
void lergab(char *gab);
void criamatriz (char **alunoresp, int *resp);
int main(){
char gab[20];
char alunoresp [100][21];
int resp[80];
//lergab(&gab);
criamatriz (&alunoresp, &resp);
printf ("\n\n%d\n", alunoresp[0][0]);
printf ("%c\n", alunoresp[0][1]);
printf ("%c\n", alunoresp[0][1]);
printf ("%c\n", alunoresp[0][19]);
return 0;
}
void lergab (char *gab){
int i;
for(i=0; i<20; i++)
scanf("%c\n" , &gab[i]);
printf("%c", gab[19]);
}
void criamatriz (char **alunoresp,int *resp){
int i = 0, j;
//for (i = 0; i <= 100; i++){
scanf ("%c", &alunoresp[i][0]);
for (j = 0; j < 80; j++){
scanf ("%d", &resp[j]);
}
for (j = 0; j < 80; j=j+4){
int g = 1;
if ((resp[j] + resp[j+1] + resp[j+2] + resp[j+3]) != 1)
alunoresp[i][g] = 'e';
else if (resp[j] == 1)
alunoresp[i][g] = 'a';
else if (resp[j+1] == 1)
alunoresp[i][g] = 'b';
else if (resp[j+2] == 1)
alunoresp[i][g] = 'c';
else if (resp[j+3] == 1)
alunoresp[i][g] = 'd';
g++;
}
//}
}
There are two issues with your program:
You are calling criamatriz function incorrectly - rather than passing a pointer to the end of the arrays, you should be passing arrays themselves, and
Your criamatriz function takes a 2D array incorrectly - you are passing it like a pointer to a pointer, which is incorrect. You should be passing it like a pointer to an array of 21 elements.
Here is how you should declare and define your criamatriz function:
void criamatriz(char (*alunoresp)[21], int *resp);
Call it like this:
criamatriz(alunoresp, resp);
criamatriz (&alunoresp[100][21], &resp[80]);
^^^^^^^^^
You're exceeding the maximum allowed indeces in your array there. e.g.
int x[10]; // allows index 0->9
Welcome to SO, Lucas!
I'm getting segmentation error every time i try to run it on gcc, any ideas?
Step 0 is to get yourself a debugger, this won't be the last time you encounter a similar issue. If you're using gcc, it's a good bet that gdb is available on this system. Try running your executable with gdb and X marks the spot!
gdb ./my_binary
... then ..
run
execution will halt right where the invalid memory access occurred. You can examine the state of the program (local variables, etc) using the print command and you can walk up and down the stack with up and down respectively.
For example:
(gdb) run
Starting program: ./go
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004fd in inner () at ./go.c:6
6 int ohno = *bad;
(gdb) bt
#0 0x00000000004004fd in inner () at ./go.c:6
#1 0x0000000000400512 in outer () at ./go.c:11
#2 0x000000000040052d in main (argc=1, argv=0x7fffffffdf88) at ./go.c:16
(gdb) backtrace
#0 0x00000000004004fd in inner () at ./go.c:6
#1 0x0000000000400512 in outer () at ./go.c:11
#2 0x000000000040052d in main (argc=1, argv=0x7fffffffdf88) at ./go.c:16
When sending an array to a function, all you need to do is send the base address of that array,
In your code
criamatriz (&alunoresp[100][21], &resp[80]);
this line is actually sending the address of the alunoresp[100][21] element, which doesnt even exist.
An array defined as int alunoresp[100][21] has maximum indices [99][20] since indices start from 0
You need to call the function like this,
criamatriz (alunoresp, resp);
Since the name of the array contains the base address (address poitning to the first element) of that array.

Resources