Better understanding of strstr in C - c

I already asked on question earlier about the string function strstr, and it just turned out that I had made a stupid mistake. Now again i'm getting unexpected results and can't understand why this is. The code i've written is just a simple test code so that I can understand it better, which takes a text file with a list of 11 words and i'm trying to find where the first word is found within the rest of the words. All i've done is move the text document words into a 2D array of strings, and picked a few out that I know should return a correct value but are instead returning NULL. The first use of strstr returns the correct value but the last 3, which I know include the word chant inside of them, return NULL. If again this is just a stupid mistake I have made I apologize, but any help here on understanding this string function would be great.
The text file goes is formatted like this:
chant
enchant
enchanted
hello
enchanter
enchanting
house
enchantment
enchantress
truck
enchants
And the Code i've written is:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[]) {
FILE* file1;
char **array;
int i;
char string[12];
char *ptr;
array=(char **)malloc(11*sizeof(char*));
for (i=0;i<11;i++) {
array[i]=(char *)malloc(12*sizeof(char));
}
file1=fopen(argv[1],"r");
for (i=0;i<11;i++) {
fgets(string,12,file1);
strcpy(array[i],string);
}
ptr=strstr(array[1],array[0]);
printf("\nThe two strings chant and %s yield %s",array[1],ptr);
ptr=strstr(array[2],array[0]);
printf("\nThe two strings chant and %s yield %s",array[2],ptr);
ptr=strstr(array[4],array[0]);
printf("\nThe two strings chant and %s yield %s",array[4],ptr);
ptr=strstr(array[5],array[0]);
printf("\nThe two strings chant and %s yields %s",array[5],ptr);
return 0;
}

Get rid of the trailing \n after fgets().
for (i=0;i<11;i++) {
fgets(string, sizeof string, file1);
size_t len = strlen(string);
if (len > 0 && string[len-1] == '\n') string[--len] = '\0';
strcpy(array[i], string);
}

char *chomp(char *str){
char *p = strchr(str, '\n');
if(p)
*p = '\0';
return str;
}
...
strcpy(array[i], chomp(string));

Related

C read file content into an array of strings

I need to load the contents of a file into two string arrays. I tried the following and it is not working.
file.txt contains 10 records and each record has two string values separated by whitespace.
CODE:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
char line[12][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
char arr[20][20];
while (fgets(line, sizeof(line), fptr)) {
strcpy(arr[i],line);
i++;
}
tot=i;
for (int i=0; i<tot; i++) {
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
printf("\n");
}
return 0;
}
If I understand correctly, you're trying to store data in a structure like:
{{"line1A", "line1B"}, {"line2A", "line2B"}, {"line3A", "line3B"}}
It looks like you need an array where each element consists of two arrays (strings), one for the first value and one for the second value on each line. If this is the case, you need a three dimensional array of chars.
In the example below I've declared arrayOfLines as array with 12 elements each of which has 2 arrays of chars (for your two values per line), with space for 20 chars in each string (NULL terminated char array)
There are some other problems with your code:
The first parameter for fgets() should be a char * - a pointer to a string buffer. Your code passes in a multi-dimensional array of chars.
Your while loop should continue until fgets returns NULL
You need to split each line into multiple strings
Check for buffer overruns when copying strings with strcpy()
In the example code I used strtok() delimited by a " " space character - you may need to play around with this - strtok can accept an array of chars to be used as a delimiter. In the example, I split the first string using the first space char, and the second string is delimited by the end of line.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
// Array for 12 lines, each with 2 strings, each string max 20 chars
// Adjust values as required.
char arrayOfLines[12][2][20];
FILE *fptr = NULL;
int i = 0;
int tot = 0;
fptr = fopen("file.txt", "r");
// char arr[20][20]; not needed
char line[20];
while(fgets(line, sizeof(line) / sizeof(line[0]), fptr) != NULL)
{
// Rudimentary error checking - if the string has no newline
// there wasn't enough space in line
if (strchr(line, '\n') == NULL) {
printf("Line too long...");
return EXIT_FAILURE;
}
// Split string into tokens
// NB: Check for buffer overruns when copying strings
char *ptr1 = strtok(line, " ");
strcpy(arrayOfLines[i][0], ptr1);
char *ptr2 = strtok(NULL, "\n");
strcpy(arrayOfLines[i][1], ptr2);
i++;
}
tot=i; // Unecessary - just use a different variable in your loop and use i as the upper bound
for (int i=0;i<tot;i++)
{
printf("first value %s\n", arrayOfLines[i][0]);
printf("second value is %s\n", arrayOfLines[i][1]);
printf("\n");
}
return 0;
}
printf("first value %s",arr[i][0]);
printf("second value is %s",arr[i][1]);
Basicly all you are doing is printing 2 chars from i word when you want to print full string you should do it like this: printf("%s",arr[i]); You said that value is separated by whitespace so when you are getting line from file you will save it to arr[i] (if first line in file contains "Hello World", your arr[0] will contain "Hello World") when you want to split it into 2 printf you need to print them char by char until space.
Edit: I reminded myself about function sscanf you can use it to get data from file array like you whould do it with keyboard input
You can use this to do that
Code
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(void){
char line[12][20];
char arr[20][20];
FILE *fptr=NULL;
int i=0;
fptr = fopen("file.txt", "r");
if(!fptr){
printf("cant open file\n");
exit(1);
}
while(fgets(*line, sizeof(line), fptr)){
strncpy(arr[i],*line, sizeof(*line));
i++;
}
for (int j=0;j<i;j++){
printf("%s\n", arr[j]);
}
return 0;
}
Notes and changes I made on your code:
Check fptr as return value of open() if it's NULL decide what to do.
Remove unnecessary tot variable and use another index j in last for loop.
Use strncpy() as a better version of strcpy()
Correct way of print arr, printf("%s\n", arr[j]);
\n can be embed on first printf()

Print last character from word from char array

I'v got this:
char file_name[50];
strncpy(file_name, dp2->d_name, sizeof(file_name2));
// put some words in it, for example "E348C", "E348", "E348A"......
And I need to find last character from each word and check it later if it is number or letter..... but the words as you can see have not the same length....
I have no idea how to get last character...
Also char the variable file_name[50]; could be defined as char * file_name; I don't care....
Any ideas ?
Edit: It seems that the question has already been solved in the comments above, but maybe somebody comes along with a similar question in the future...
Please look at the comments.
#include <stdio.h>
#include <string.h>
int main(void) {
char file_name[50];
char inp[] = "something3";
strncpy(file_name, inp, sizeof(inp));
printf("%s\n", file_name);
// strlen returns the length of a string.
char end_char = file_name[strlen(file_name)-1];
printf("%c\n", end_char);
if (isdigit(end_char)) { // checks if end_char is a number
printf("last character is a number\n");
}
if (isalpha(end_char)){ // checks if end_char is a letter
printf("last character is a character\n");
}
return 0;
}
Sample output for inp[] = "something3":
something3
3
last character is a number
Sample output for inp[] = "somethingX":
somethingX
X
last character is a character

How to extract a substring from a string in C?

I tried using strncmp but it only works if I give it a specific number of bytes I want to extract.
char line[256] = This "is" an example. //I want to extract "is"
char line[256] = This is "also" an example. // I want to extract "also"
char line[256] = This is the final "example". // I want to extract "example"
char substring[256]
How would I extract all the elements in between the ""? and put it in the variable substring?
Note: I edited this answer after I realized that as written the code would cause a problem as strtok doesn't like to operate on const char* variables. This was more an artifact of how I wrote the example than a problem with the underlying principle - but apparently it deserved a double downvote. So I fixed it.
The following works (tested on Mac OS 10.7 using gcc):
#include <stdio.h>
#include <string.h>
int main(void) {
const char* lineConst = "This \"is\" an example"; // the "input string"
char line[256]; // where we will put a copy of the input
char *subString; // the "result"
strcpy(line, lineConst);
subString = strtok(line,"\""); // find the first double quote
subString=strtok(NULL,"\""); // find the second double quote
printf("the thing in between quotes is '%s'\n", subString);
}
Here is how it works: strtok looks for "delimiters" (second argument) - in this case, the first ". Internally, it knows "how far it got", and if you call it again with NULL as the first argument (instead of a char*), it will start again from there. Thus, on the second call it returns "exactly the string between the first and second double quote". Which is what you wanted.
Warning: strtok typically replaces delimiters with '\0' as it "eats" the input. You must therefore count on your input string getting modified by this approach. If that is not acceptable you have to make a local copy first. In essence I do that in the above when I copy the string constant to a variable. It would be cleaner to do this with a call to line=malloc(strlen(lineConst)+1); and a free(line); afterwards - but if you intend to wrap this inside a function you have to consider that the return value has to remain valid after the function returns... Because strtok returns a pointer to the right place inside the string, it doesn't make a copy of the token. Passing a pointer to the space where you want the result to end up, and creating that space inside the function (with the correct size), then copying the result into it, would be the right thing to do. All this is quite subtle. Let me know if this is not clear!
if you want to do it with no library support...
void extract_between_quotes(char* s, char* dest)
{
int in_quotes = 0;
*dest = 0;
while(*s != 0)
{
if(in_quotes)
{
if(*s == '"') return;
dest[0]=*s;
dest[1]=0;
dest++;
}
else if(*s == '"') in_quotes=1;
s++;
}
}
then call it
extract_between_quotes(line, substring);
#include <string.h>
...
substring[0] = '\0';
const char *start = strchr(line, '"') + 1;
strncat(substring, start, strcspn(start, "\""));
Bounds and error checking omitted. Avoid strtok because it has side effects.
Here is a long way to do this: Assuming string to be extracted will be in quotation marks
(Fixed for error check suggested by kieth in comments below)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[100];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
j =i+1;
while(input[j]!='"'){
if(input[j] == '\0'){
endFlag++;
break;
}
extract[k] = input[j];
k++;
j++;
}
}
}
extract[k] = '\0';
if(endFlag==1){
printf("1.Your code only had one quotation mark.\n");
printf("2.So the code extracted everything after that quotation mark\n");
printf("3.To make sure buffer overflow doesn't happen in this case:\n");
printf("4.Modify the extract buffer size to be the same as input buffer size\n");
printf("\nextracted string: %s\n",extract);
}else{
printf("Extract = %s\n",extract);
}
return 0;
}
Output(1):
$ ./test
Input string: extract "this" from this string
Extract = this
Output(2):
$ ./test
Input string: Another example to extract "this gibberish" from this string
Extract = this gibberish
Output(3):(Error check suggested by Kieth)
$ ./test
Input string: are you "happy now Kieth ?
1.Your code only had one quotation mark.
2.So the code extracted everything after that quotation mark
3.To make sure buffer overflow doesn't happen in this case:
4.Modify the extract buffer size to be the same as input buffer size
extracted string: happy now Kieth ?
--------------------------------------------------------------------------------------------------------------------------------
Although not asked for it -- The following code extracts multiple words from input string as long as they are in quotation marks:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char input[100];
char extract[50];
int i=0,j=0,k=0,endFlag=0;
printf("Input string: ");
fgets(input,sizeof(input),stdin);
input[strlen(input)-1] = '\0';
for(i=0;i<strlen(input);i++){
if(input[i] == '"'){
if(endFlag==0){
j =i+1;
while(input[j]!='"'){
extract[k] = input[j];
k++;
j++;
}
endFlag = 1;
}else{
endFlag =0;
}
//break;
}
}
extract[k] = '\0';
printf("Extract = %s\n",extract);
return 0;
}
Output:
$ ./test
Input string: extract "multiple" words "from" this "string"
Extract = multiplefromstring
Have you tried looking at the strchr function? You should be able to call that function twice to get pointers to the first and second instances of the " character and use a combination of memcpy and pointer arithmetic to get what you want.

passing tokens from array to strcmp

What I am trying to do is to break the user input in parts with whitespace as a delimiter, copy the parts into the array (tokenAr) and compare the tokenAr[0] (the first part) if it is equal to sHistory. if they are equal, check the value of tokenAr[1] if it is "1", "2" etc, to execute the corresponding command that is entered in the history array. This is what i have tried to far and it crashes. I am using TCC on Windows x64.
EDIT: I forgot to mention that I began learning C, just two days ago.
EDIT2: I run the program in a debugger and it has raised an Acces Violation(Segmentation Fault) in line if(strcmp(tokenArPtr[0],sHistory)==0)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int i=1; int j=1; int k=0;
char history[100][100] = {0};
char sKey[] = "exit";
char sInput[100];
char sHistory[]="history";
do
{
//gather user input
printf ("hshell> ");
fgets (sInput, 100, stdin);
strcpy(history[i],sInput);
i++;
//END_gather user input
//Tokenizing
char delims[] = " ";
char *tokenArPtr[5];
char *result = NULL;
result = strtok(sInput, delims);
tokenArPtr[0] = result;
while (result!=NULL)
{
puts(result);
result= strtok(NULL, delims);
tokenArPtr[k+1] = result;
puts(tokenArPtr[k]);
puts("=====");
k++;
}
k=0;
/*
//END_Tokenizing
if(strcmp(tokenArPtr[0],sHistory)==0)
{
for(j=1;j<i;j++)
{
printf("%d. %s \n",j,history[j]);
}
}
else if (strcmp (sKey,tokenArPtr[0]) != 0)
{
printf("\nCommand not found \n");
}*/
}while (strcmp (sKey,sInput) != 0);
return 0;
}
EDIT 3: I used the result variable instead of the tokenArPtr directly, but when debugging, I noticed that the values of the array are not being updated.
Which type does strtok return? char *. What is the type of tokenAr[k]? char. What type does strcmp expect as input? char * and char *. What is the type of tokenAr[0]? char.
See a problem? You should. The * is pretty significant.
Assuming tokenAr is declared like char *tokenAr[2];, how many char * values can tokenAr store? What happens when k exceeds 2? You need to ensure you don't overflow your tokenAr array.
history is uninitialised. Using an uninitialised variable is undefined behaviour. I suggest initialising it, like this: char history[100][100] = { 0 };
Which book are you reading?
While tokenizing, the loop will never end because the test is on the variable "result" that will never change... So you're finally going to a buffer overflow with "tokenAr"... Modify your code to test "tokenAr".
Edit: And tokenAR should be an array... (I don't know how it can compile...)
There are many problems... First of all you should include string.h which will show you some errors in compilation.
I believe that the main problem is here:
char tokenAr[2];
result = strtok(sInput, delims);
while (result!=NULL)
{
tokenAr[k] = strtok(NULL, delims);
k++;
}
tokenAr should be an array of pointers, not chars. And are you sure that k will never exceed 2? An assertion would help debugging.

help with C string i/o

Reads through a .txt file and puts all chars that pass isalpha() in a char array. for spaces it puts \0, so the characters in the array are separated by strings. This works.
I need help with the second part. I need to read a string that the user inputs (lets call it the target string), find all instances of the target string in the char array, and then for each instance:
1. print the 5 words before the target string
2. print the target string itself
3. and print the 5 words after the target string
I can't figure it out, i'm new to C in general, and I find this i/o really difficult after coming from Java. Any help would be appreciated, here's the code I have right now:
#include <stdio.h>
#include <string.h>
main(argc, argv)
int argc;
char *argv[];
{
FILE *inFile;
char ch, ch1;
int i, j;
int arrayPointer = 0;
char wordArray [150000];
for (i = 0; i < 150000; i++)
wordArray [i] = ' ';
/* Reading .txt, strip punctuation, conver to lowercase, add char to array */
void extern exit(int);
if(argc > 2) {
fprintf(stderr, "Usage: fread <filename>\n");
exit(-1);
}
inFile = fopen(argv[1], "r");
ch = fgetc(inFile);
while (ch != EOF) {
if(isalpha(ch)) {
wordArray [arrayPointer] = tolower(ch);
arrayPointer++;
}
else if (isalpha(ch1)) {
wordArray [arrayPointer] = '\0';
arrayPointer++;
}
ch1 = ch;
ch = fgetc(inFile);
}
fclose;
/* Getting the target word from the user */
char str [20];
do {
printf("Enter a word, or type \"zzz\" to quit: ");
scanf ("%s", str);
char* pch;
pch = strstr(wordArray, str);
printf("Found at %d\n", pch - wordArray + 1);
pch = strstr(pch + 1, str);
} while (pch != NULL);
}
There are a number of problems here, but the one that is probably tripping you up the most is the use of strstr as you've got it. Both parameters are strings; the first is the haystack, and the second is the needle. The definition of a C string is (basically) a sequence of characters terminated by '\0'. Take a look at how you've constructed your wordArray; it's effectively a series of strings one right after the other. So when you are using strstr the first time, you are only ever looking at the first string.
I realize this isn't the entire answer you are looking for, but hopefully it points you in the right direction. You may want to consider building up an array of char * that points into your wordArray at each word. Iterate over that new array checking for the string the user is looking for. If you find it, you now have an index you can work backwards and forwards from.

Resources