Iteratively iterating Array of Strings (pointer value seems to get "stuck") - c

EDIT:
I realize that the code in my OP is long and hard to read. I've highlighted the problem with 4 lines of code.
char **t = {"Hello", "World"};
char **a = t;
++(a[0]);
printf("%c\n",**t);
I want to increment through the array of strings without losing the pointer to the first character. Therefore, I initialize a new pointer 'a' to point to the first character. After I increment the 'a' pointer, though, it seems to change what 't' points to! In the printf statement, I expect that t's pointer value remain unchanged, but it seemed to increment with 'a' and now points to the second character. Why is this happening?
SOLVED:
In the above example, a and t seem to be the same pointer so if I change one (by incrementing for example), the change is also reflected in the pther. However, if I dereference t into another variable, then I can change said variable without having that change reflected in t. In the above example, this looks like
char *a = t[0];
++a;
printf("a value: %c\n", *a);
printf("t value: %c\n", **t);
I think that I had originally been confused about dereferencing since t points to a pointer. Every response I've gotten is to use array indexing as opposed to pointers, and I can see why.
ORIGINAL POST:
Say I have:
array1 {"arp", "live", "strong"}, and
array2 {"lively", "alive", "harp", "sharp", "armstrong"}
I'm trying to find the strings in array1 that are substrings of any string in array2.
To do this, I wrote a helper function (compString) that takes in the string from array1, the entire array2, and the length of array2.
Essentially, what the function does is create local pointer values for both the string pointer and the array pointer. It then extracts the first string from array2 and begins to walk through it to find a match for the first letter of the input string. If no match is found, the function will move on to the next string, until a full match is found or until it walks through the entire array2. It then returns to its calling environment.
I ran into some unexpected behavior. When I call the function (with the same arguments), after having already called it, the array pointer seems to point to exactly where it left off in the previous call.
For example, if I call compString("arp", array2, 5) then the function will flag a match starting at the a in harp.
Then, if I call compString("live", array2, 5), the function begins at the a in harp and goes to the end of the array without flagging a match.
Finally, when I call compString("strong", array2, 5), array2 is now pointing to garbage since it has already been iterated through, and does not flag a match.
Since one of the first things the helper function does is "localize" the pointers being passed (that is, create a local pointer variable and assign to it the value of the pointer being passed to the funcion, then iterate that local variable), I would assume that subsequent calls to the function wouldn't "save" the previous value of the pointer. Any pointers?
Source attached:
#include <stdio.h>
#include <string.h>
int compString(char *, char **, int);
int main(void)
{
int sz1 = 3;
int sz2 = 5;
char *p, *p2;
char *array1[] = {"arp\0", "live\0", "strong\0"};
char *array2[] = {"lively\0", "alive\0", "harp\0", "sharp\0", "armstrong\0"};
compString("arp\0",array2,5);
compString("live\0",array2,5);
compString("strong\0",array2,5);
}
int compString(char *arr1, char **arr2, int sz2)
{
printf("\n\n\n");
printf("WORD: %s\n",arr1);
int i = 0;
char *a1 = arr1;
char **a2 = arr2;
char *p;
char *p2;
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",a2[i]);
while (i < sz2)
{
printf("%c\n",*a2[i]);
if (*a1 == *a2[i])
{
char *p = a1;
char *p2 = a2[i];
while ((*p == *p2) && (*p != '\0'))
{
++p;
++p2;
}
if (*p == '\0')
{
return 1;
}
else
{
*++(a2[i]);
if (*(a2[i]) == '\0')
{
++i;
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",a2[i]);
}
}
}
else
{
*++(a2[i]);
if (*(a2[i]) == '\0')
{
++i;
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",a2[i]);
}
}
}
return 0;
}

Your loop is causing an off-by-one error. What you want to do is looping through your array of 5 strings, so from 0 to 4. We can see that when you run all three tests because they somehow depend on the result on eachother (I didn't look into the comparing logic too much, it seems rather obfuscated).
We can replicate the behavior with just one test:
compString("test", array2, 5);
So the 5 is supposed to tell it to loop from 0 to 4. In the comparison function, you have this:
int i = 0;
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);
while (i < sz2)
So far, so good. The i < sz2 is correct, it supposedly loops from 0 to 4, assuming you increase i correctly.
Then, however, you do this somewhere at the end of the function:
++i;
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);
So when i is 4, you increase it to 5, and at that point the function should stop looping through the array, but at that point you do that print that tries to access a2[5], which doesn't exist. That's where it crashes for me on MSVC.
My suggestion is that you rework your loop logic to something like this:
for (int i = 0; i < sz2, i++){
printf("BEGIN ITERATION %d\n", i);
printf("Checking against word: %s\n", a2[i]);
// do something with a2[i] and don't manually change the value of "i"
}
Also, I would tidy up that string logic, there might be a bug in it somewhere. You don't need all those suspicious dereferencing calls. When you want to access character x of string y in a2, then a2[y][x] does the trick. For instance, if you want to find some letter, simply do:
for (int n = 0; n < strlen(a2[y]), n++){
if (a2[y][n] == 'a')
printf("found letter 'a' at position %d\n", n);
}
Furthermore, you don't need to add \0 to string literals. Those are automatically added, so you're just adding a second one. Instead of this:
char *array1[] = {"arp\0", "live\0", "strong\0"};
Do this:
char *array1[] = {"arp", "live", "strong"};
Also, I don't know if you have to implement this function because it's a task you've been given, but if you just want to find substrings, then you don't need to reinvent the wheel as strstr already does that.

are you looking for something like this:
char *array1[] = {"arp", "live", "strong", NULL};
char *array2[] = {"lively", "alive", "harp", "sharp", "armstrong", NULL};
void findsrings(char **neadles, char **haystack)
{
while(*neadles)
{
char **hay = haystack;
size_t pos = 0;
printf("Searching for %s\n", *neadles);
while(*hay)
{
if(strstr(*hay, *neadles))
{
printf("Found!! Haystack word is: %s at index %zu in haystack\n", *hay, pos);
}
pos++;
hay++;
}
neadles++;
}
}
int main()
{
findsrings(array1, array2);
return 0;
}
you do not need the '\0' at the end of the string literals as they are added automatically by the C compiler. I have added NULL wihch terminates the array of the string pointers - so you do not need to provide the sizes of the arrays/.

As mentioned in the comments the side effect you've noticed, is due to this line *++(a2[i]); which is altering the contents of your second array. As time progresses you'll eventually end up with the second array having no actual words in it.
Generally your code is overly complicated and you're using while loops when for loops are better suited.
The outer loop for example would work better as:
for(i=0;i<sz2;i++)
{
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",arr2[i]);
And then since you want to check each substring in arr2[i], you can use a for loop for that...
for(wordstart=arr2[i];*wordstart!='\0';wordstart2++)
{
Finally, you have an inner loop that compares each character of arr1 with the substring defined by the wordstart. You need to make sure that neither p1 or p2 goes beyond the end of their respective strings and that they point to the same character.
for(p1=arr1,p2=wordstart;(*p1!='\0')&&(*p2!='\0')&&(*p1==*p2);p1++,p2++);
Once any of those 3 conditions is no longer true, if you check that p1 has reached the end of the string, you know that it must have found a substring.
if(*p1=='\0')
{
printf("Matched %s\n",arr2[i]);
return 1;
}
The resulting function looks like:
int compString(char *arr1, char **arr2, int sz2)
{
printf("\n\n\n");
printf("WORD: %s\n",arr1);
int i = 0;
char *p1;
char *wordstart;
char *p2;
for(i=0;i<sz2;i++)
{
printf("BEGIN ITERATION %d\n",i);
printf("Checking against word: %s\n",arr2[i]);
for(wordstart=arr2[i];*wordstart!='\0';wordstart++)
{
for(p1=arr1,p2=wordstart;(*p1!='\0')&&(*p2!='\0')&&(*p1==*p2);p1++,p2++);
if(*p1=='\0')
{
printf("Matched %s\n",arr2[i]);
return 1;
}
}
}
return 0;
}
Other things to note is that you don't need to implicitly add the \0 to a string. The following is just fine.
char *array1[] = {"arp", "live", "strong"};
You could also add NULL as the last element in the list of strings so that you don't need to track how many strings there are.
char *array2[] = {"lively", "alive", "harp", "sharp", "armstrong"};
which means the outer loop could be simplified to
for(i=0;arr2[i];i++)

Related

Clear char array in C without any standard library

I'm working on a class project that would require me to make unique strings and I want to concatenate a number to a string. However I do NOT have access to C Standard Library (memset, malloc, etc.). I made this which works:
char* concat(char* name, int num) {
int i, j;
char newName[50], stack[5];
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
name[0] = '\0';
return newName;
}
But then as I tested it with multiple strings, I realized that newName was being reused over and over. For ex.
This test file outputs the following:
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca); /* bill2ca1 */
Write(bill); /* bill2ca1 */
}
It successfully appends the 1 to rebecca, but then when I call concat on bill, it overwrites the first 5 letter but keeps the same chars from before in newName.
QUESTION: How to clear a char array so the next time it's called it will be set to empty, or dynamically allocate it (without using C Standard Library)?
Without using malloc, you can simply put the memory on the stack of the calling function, to keep in the scope where it is needed. It's easier to add the buffer pointer to the argument list like so:
char* concat(char *newName, char* name, int num) {
int i, j;
char stack[5];
:
:
}
int main() {
char rebecca[50];
char bill[50];
concat(rebecca, "rebecca", 1);
concat(bill, "bill", 2);
write(rebecca);
write(bill);
}
Generally speaking, assign memory where it will be used. Embedded programming (which might need to run for months without a reboot) avoids malloc like the plague, just because of the risk of memory leaks. You then need to assign extra space since you may not know the size at compile time, and then ideally check for running past the end of the buffer. Here we know the string sizes and 50 chars is more than enough.
Edit:
The other issue is that you're not null terminating. The print will go until it hits 0x00. Your line
name[0] = '\0';
should be
newName[i] = '\0';
You've got a major issue that you're overlooking. In your function, newName is a local variable (array) and you're returning it from the function. This invokes undefined behavior. The beauty of UB is that, sometime it appears to work as expected.
You need to take a pointer and allocate memory dynamically instead, if you want to return it from your concat() function. Also, in the main(), after using it, you need to free() it.
A better alternative, maybe, if you choose to do so, is
Define the array in the caller.
Pass the array to the function.
Inside the function, memset() the array before you perform any other operation.
One thing to remember, this way, every call to the function will clean the previous result.
EDIT:
If you cannot use memset(), in the main, you can use a for loop like
for (i = 0; i < sizeof(arr)/sizeof(arr[0]); i++)
arr[i] = 0;
to clear the array before passing it on next time.
You're returning the address of a local variable. Since the variable goes out of scope when the function returns, this invokes undefined behavior.
You function should dynamically allocate memory for the result of the concatenation, then return that buffer. You'll need to be sure to free that buffer later to prevent a memory leak:
char* concat(char* name, int num) {
int i, j;
char *newName, stack[5];
// allocate enough space for the existing string and digits for a 64-bit number
newName = malloc(strlen(name) + 30);
for(i=0; name[i]!='\0'; ++i) {
newName[i] = name[i];
}
for (j=0; num>=1 || num==0; j++) {
stack[j] = (num % 10) + '0';
num = num / 10;
if (num==0) break;
}
while (j>=0) {
newName[i++] = stack[j--];
}
newName[i] = '\0';
return newName;
}
int main() {
char* rebecca = concat("rebecca", 1);
char* bill = concat("bill", 2);
Write(rebecca);
Write(bill);
free(rebecca);
free(bill);
}

free causing different results from malloc

Below is a C program I have written to print different combination of characters in a string.
This is not an efficient way as this algorithm creates a lot of extra strings. However my question is NOT about how to solve this problem more efficiently.
The program works(inefficiently though) and prints the different combination of the characters of string(correctly). But when I try to free the extra strings that is getting created I run into issue. The free that is causing issue is at the end of the recur_printc function (it is commented).
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define N 3
void recur_printc(char *, int, char *);
int main()
{
char str[] = "abc";
char *print_arr = malloc(N * sizeof(char));
//Call recur_print
recur_printc(print_arr, 0, str);
free(print_arr);
return 0;
}
void recur_printc( char *print_arr, int index, char *remaining)
{
int i, j, rem_len, index_4_next;
//base case, only last character remaining
if(strlen(remaining) == 1)
{
print_arr[index] = remaining[0];
//Print the print_arr
for(i=0; i<N; i++)
{
printf("%c",print_arr[i]);
}
printf("\n");
return;
}
//If more than one character remaining
else
{
rem_len = strlen(remaining);
for(i=0; i<rem_len; i++)
{
//Add one character to print_arr
print_arr[index] = remaining[i];
//now create the string with remaining characters
char *remaining_for_next = malloc((rem_len-1) * sizeof(char));
index_4_next = 0;
for(j=0; j<rem_len; j++)
{
if(j != i)
{
remaining_for_next[index_4_next] = remaining[j];
index_4_next++;
}
}
//call recur_print
recur_printc(print_arr, index+1, remaining_for_next);
//Free the remainin_for_next
/*------This is causing issues----*/
//free(remaining_for_next);
remaining_for_next = NULL;
}
}
}
When I ran this program in gdb I noticed that when i=1 for the first instance of recur_print, a strange thing happens with the malloc.
When this line is executed :
char *remaining_for_next = malloc((rem_len-1) * sizeof(char));
Although rem_len-1 equals to 2, malloc allocates 3 bytes, and then the whole algorithm fails because the somewhere in the code strlen of this string is used (which will be 3 instead of 2). Not sure what is happening.(This does not happen when I comment out the free() line.)
Below is gdb output :
42 char *remaining_for_next = malloc((rem_len-1) * sizeof(char));
(gdb) print remaining_for_next
$3 = 0x0
(gdb) n
43 index_4_next = 0;
(gdb) print remaining_for_next
$4 = 0x602030 "# `"
(gdb) print rem_len-1
$5 = 2
(gdb) q
Sorry for the long post. Once again, my question is NOT about how to print the combination in a different(and better) way. My question is why the above code fails when I try to free the remaining_for_next string (maybe why malloc is getting affected).
I haven't gone through everything with a fine-toothed comb but I believe the remaining_for_next string will have no null character termination. You're using strlen() which doesn't include the null character in the string length and then copying the string as if it were an array of characters. It might be a place to begin searching. I'd imagine the first time that recur_printc is called from itself, the behaviour won't be what you want. Try manually appending a null character to remaining_for_next and see if that fixes the problem.
Every time you are creating your string, you are not appending a null terminator, which causes the error.
So change this:
for(j=0; j<rem_len; j++) {
if(j != i) {
remaining_for_next[index_4_next] = remaining[j];
index_4_next++;
}
}
to this:
for(j=0; j<rem_len; j++) {
if(j != i) {
remaining_for_next[index_4_next] = remaining[j];
index_4_next++;
}
}
remaining_for_next[index_4_next] = '\0';
Output:
gsamaras#gsamaras:~/Desktop/px$ gcc -Wall main.c
gsamaras#gsamaras:~/Desktop/px$ ./a.out
abc
acb
bac
bca
cab
cba
Tip: It's almost always a must to null terminate your strings, do not forget it!
Important edit:
As alk noticed, you need to change this:
char *remaining_for_next = malloc((rem_len - 1) * sizeof(char));
to this:
char *remaining_for_next = malloc((rem_len) * sizeof(char));
in order to make space for the null terminator.
Nice question, +1.

C language - turning input into code

Most of the times, the questions I ask have to do with a specific part of a code that i did incorrectly, or some bug that i overlooked, but this time, I don't know where to start. I don't even know if what I am trying to do is possible.
I was given an assignment to write a code that gets a string that resembles a variable declaration, for example int x,y; is a valid input. char c,*cptr,carray[80]; is another example of valid input.
The code will create what the user inputs, and will print how much memory it took.
For instance, in the first example (int x,y;) the code will create 2 integers, and print "x requires 4 bytes, y requires 4 bytes".
In the second example, the code will create a character, a pointer to a character, and a string with 80 characters, and will print "c requires 1 byte, cptr requires 4 bytes, carray requires 80 bytes"
Is this even possible? It is not valid code to declare variables after the beginning of the code. They must be declared before anything else in C. So I don't see a way to do this...
This is a parsing problem -- you need to parse the input string and figure out what it means. You don't need to actually "create" anything, you just need to figure out the sizes of the variables that the compiler would create for that code.
Parsing actually a very large subject, with lots of books written about it and tools written to make it easier. While you could use a tool like antlr or bison to complete this task, they're probably overkill -- a simple recursive descent hand-written parser is probably the best approach.
Something like:
const char *parse_declaration(const char *p) {
/* parse a declaration, printing out the names and sizes of the variables
* 'p' points at the beginning of the string containing the declaration, and the
* function returns the pointer immediately after the end or NULL on failure */
int size;
if (!(p = parse_declspecs(p, &size))) return 0;
do {
const char *name;
int namelen, declsize;
if (!(p = parse_declarator(p, size, &name, &namelen, &declsize))) return 0;
printf("%.*s requires %d bytes\n", namelen, name, declsize);
p += strspn(p, " \t\r\n"); /* skip whitespace */
} while (*p++ == ',');
if (p[-1] != ';') return 0;
return p;
}
const char *parse_declspecs(const char *p, int *size) {
/* parse declaration specifiers (a type), and output the size of that type
* p points at the string to be parsed, and we return the point after the declspec */
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) return 0;
int len = 0;
while (isalnum(p[len])) len++;
if (!strncmp(p, "char", len)) {
*size = sizeof(char);
return p+len; }
if (!strncmp(p, "int", len)) {
*size = sizeof(int);
return p+len; }
... more type tests here ...
if (!strncmp(p, "unsigned", len)) {
p += len;
p += strspn(p, " \t\r\n");
if (!isalpha(*p)) {
*size = sizeof(unsigned);
return p; }
while (isalnum(p[len])) len++;
if (!strncmp(p, "int", len)) {
*size = sizeof(unsigned int);
return p+len; }
... more type tests here ...
}
return 0;
}
const char *parse_declarator(const char *p, int typesize, const char **name, int *namelen, int *declsize) {
/* parse a declarator */
p += strspn(p, " \t\r\n");
while (*p == '*') {
typesize = sizeof(void *); /* assuming all pointers are the same size...*/
p++;
p += strspn(p, " \t\r\n"); }
declsize = typesize;
if (isalpha(*p)) {
*name = p;
while (isalnum(*p) | *p == '_') p++;
*namelen = p - *name;
} else if (*p == '(') {
if (!(p = parse_declarator(p+1, typesize, name, namelen, declsize))) return 0;
p += strspn(p, " \t\r\n");
if (*p++ != ')') return 0;
} else
return 0;
p += strspn(p, " \t\r\n");
while (*p == '[') {
int arraysize, len;
if (sscanf(++p, "%d %n", &arraysize, &len) < 1) return 0;
p += len;
declsize *= arraysize;
if (*p++ != ']') return 0;
p += strspn(p, " \t\r\n"); }
return p;
}
should get you started...
If you are trying to execute input code dynamically, to my knowledge that would not be possible without storing the code and then compiling again. This however seems like a very nasty and lengthy approach. If all you are trying to do however is calculate the size of declarations from input, what I would do is take the string received, call a function that analyzes/decomposes the string. So for example if the string has "int", "char", etc.. I know would know what kind of declaration I am dealing with, and after I know what declaration I am dealing with I could just count the number of variables declared and keep a counter in your example it was x,y. I would a loop on the counter and calculate the sizeof the type of declaration and how many were declared.
Sure, it's possible; it's just a bit of work. You're going to have to study C declaration syntax, and then write the code to recognize it (basically a small compiler front end).
For example, in the declaration
char c, *cptr, carray[80];
you have a sequence of tokens:
char c , * cptr , carray [ 80 ] ;
which will be recognized as a type specifier (char) followed by three declarators; a direct declarator, a pointer declarator, and an array declarator.
You can create the space for the objects dynamically using malloc or calloc. Then you'll need to create some kind of table to map the identifier (the variable name) to the dynamically-created object. You won't be able to treat these things as regular variables in regular C code; you're going to be doing a lot of table lookups and dereferencing.
Sure, you could do this with a type of parser. Assuming that you do not want to actually execute the code that you are given, you could read the string and then count how many times a variable of each specific type is declared, and calculate the amount of memory thusly. But, depending on the requirements of the professor, you may run into a view different issues.
In particular, the sizes of different types will likely be different on each processor. With the exception of char, you need to account for this. This is easy if you are analyzing the memory requirements for the computer that your program is executing on, as you could just have const variables whose values are assigned via sizeof to get the sizes, but if not, your program is more difficult, especially since you cannot presume to know the size of any variable.
Secondly, structs will be a problem do to some of the more interesting rules of C. Do you need to account for them?
So, this is entirely possible, because contrary to what you stated in your question, your code doesn't have to "create" a variable at all - it can just create an in-memory total for each type and print them out when done.
Figured I would post my solution just incase anyone is interested
void* q5(char* str_in)
{
char runner;
int i=0,memory,counter=0,arr_size;
runner=str_in[i];
while(1)
{
if(runner=='i') //the input is integer
{
memory=sizeof(int);
break;
}
if(runner=='c') //input is char
{
memory=sizeof(char);
break;
}
if(runner=='d') //input is double
{
memory=sizeof(double);
break;
}
if(runner=='s') //input is short
{
memory=sizeof(short);
break;
}
if(runner=='l') //input is long
{
memory=sizeof(long);
break;
}
if(runner=='f') //input is float
{
memory=sizeof(float);
break;
}
} //we know the type of data, skip in the string until first variable
while(runner!=' ') //advance until you see empty space, signaling next variable
{
i++;
runner=str_in[i];
}
while(runner==' ') //advance until you encounter first letter of new variable
{
i++;
runner=str_in[i];
} //runner is now first letter of first variable
while(runner!=';') //run on the string until its over
{
if(runner==',') //if its ',', then spaces will occur, skip all of them to first char that isnt space
{
i++;
runner=str_in[i];
while(runner==' ')
{
i++;
runner=str_in[i];
} //runner now points to first letter of variable
continue;
}
if(runner=='*') //current variable is a pointer
{
counter=counter+4; //pointers are always 4 bytes regardless of type!
i++;
runner=str_in[i];
while((runner!=',')&&(runner!=';')) //while runner is still on this variable
{
printf("%c",runner);
i++;
runner=str_in[i];
}
printf(" requires 4 bytes\n"); //now runner is the first character after the variable we just finished
continue;
}
while((runner!=',')&&(runner!=';')) //now is the case that runner is the first letter of a non pointer variable
{
printf("%c",runner);
i++;
runner=str_in[i];
if((runner==',')||(runner==';')) //we are done
{
printf(" requires %d bytes\n",memory);
counter+=memory;
continue;
}
if(runner=='[') //this variable is an array
{
printf("[");
i++;
runner=str_in[i]; //runner is now MSB of size of array
arr_size=0;
while(runner!=']')
{
printf("%c",runner);
arr_size*=10;
arr_size=arr_size+runner-48; //48 is ascii of 0
i++;
runner=str_in[i];
} //arr_size is now whats written in the [ ]
printf("] requires %d bytes\n",arr_size*memory);
counter+=arr_size*memory;
i++;
runner=str_in[i]; // should be ',' since we just finished a variable
continue;
}
}
}
printf("Overall %d bytes needed to allocate\n",counter);
return (malloc(counter));
}

What in my program is causing exception c0000005? (Probably a memory error)

My code:
#include <stdio.h>
#include <stdint-gcc.h>
#include <string.h>
int checkAnagram(char *word1, char *word2, int length){ //This function compares the two strings by storing the occurrences of their letters in a histogram, and then comparing that histogram.
printf("test4");
int i, n;
int letterCount1[26], letterCount2[26];
char letter;
for(i=0;i<length;i++){
letter = word1[i];
letterCount1[letter-'a']++;
}
for(n=0;n<length;n++){
letter = word2[n];
letterCount2[letter-'a']++;
}
for(i=0;i<26;i++){
for(n=0;n<26;n++){
if(letterCount1[i]==letterCount2[n]){
i++;
} else {
return 0;}
}
}
return 1;
}
void main(){
int length1, length2,i,n;
scanf("%d", &length1);
int lengthArray1[length1]; //Array used to store the length of each string (without white spaces)
char *sentenceArray1[length1];
char tempString[100000];
//The array for storing the first set of sentences, and a temporary string used
//for allocating memory in the next loop
for(i=0;i<=length1;i++){
fgets(tempString, 100000, stdin); //Reads the first line of input (up to and including \0), with a maximum line length which will probably be sufficient.
sentenceArray1[i]=malloc((strlen(tempString))*sizeof(char)); //Allocates just enough memory for each string (including \0).
int index = 0;
for(n=0;n<(strlen(tempString));n++){
if(tempString[n] != ' ' && tempString[n] != '.') { //Copies only from the input if the character is not a whitespace.
sentenceArray1[i][index++]=tolower(tempString[n]);
}
}
sentenceArray1[i][index] = '\0';
lengthArray1[i]=strlen(sentenceArray1[i]);
printf("test1\n");
}
scanf("%d", &length2);//Same stuff as above, now for the second set of strings.
int lengthArray2[length2], index;
char *sentenceArray2[length2];
for(i=0;i<=length2;i++){
fgets(tempString, 100000, stdin);
sentenceArray2[i]=malloc((strlen(tempString))*sizeof(char));
index = 0;
for(n=0;n<(strlen(tempString));n++){
if(tempString[n] != ' ' && tempString[n] != '.') {
sentenceArray2[i][index++]=tolower(tempString[n]);
}
}
sentenceArray2[i][index] = '\0';
lengthArray2[i]=strlen(sentenceArray2[i]);
printf("test2\n");
}
printf("test3");
for(i=0;i<length1;i++){
for(n=0;n<length2;n++){
if(lengthArray2[i]==lengthArray1[i]){
if(checkAnagram(*sentenceArray1[n],*sentenceArray2[i], length1)==1){ //Sends strings only to the checkAnagram function if they are of the same length.
printf("%d ",i);
}
}
}
printf("\n");
}
}
Supposed input and output:
I must have messed something up with the arrays and pointers somewhere, but the limited feedback from my console + my limited experience with C programming makes it hard to locate the error. My output gets as far to print "test4" once, and then crashes with the exception given in the title.
I hope what I want to achieve is clear, but I can't be any more precise on the error, unfortunately.
There is also a problem with:
for(i=0;i<=length1;i++){
You have one iteration past the array size:
int lengthArray1[length1];
If length1 is 5 then lengthArray1 has elements 0, 1, 2, 3, and 4, but your loop counts to 5. The condition should be i < length1, not i <= length1.
You should also use spaces around operators to make your code more readable.
The main error is at:
if(checkAnagram(*sentenceArray1[n],*sentenceArray2[i], length1)==1){
From the definition of checkAnagram it seems that it takes a character-array. But you are simply passing the value of the first char in both these arrays. So change it to:
if(checkAnagram(sentenceArray1[n],sentenceArray2[i], length1)==1){
This actually passes a pointer to the start of both the arrays. When I ran your code, and gave the input you specified it executed successfully, but the desired output wasn't coming.
Rest is up to your algorithm. Re-check it again.
This line:
if(checkAnagram(*sentenceArray1[n],*sentenceArray2[i], length1)==1){ //Sends strings only to the checkAnagram function if they are of the same length.
Errors out with "Type error in argument 1 to checkAnagram;found char expected pointer to char.
Errors out with "Type error in argument 2 to checkAnagram;found char expected pointer to char.
Remove the "*" from both argument 1 & 2.

Appending a char to a char* in C?

I'm trying to make a quick function that gets a word/argument in a string by its number:
char* arg(char* S, int Num) {
char* Return = "";
int Spaces = 0;
int i = 0;
for (i; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
//Want to append S[i] to Return here.
}
else if (Spaces > Num) {
return Return;
}
}
printf("%s-\n", Return);
return Return;
}
I can't find a way to put the characters into Return. I have found lots of posts that suggest strcat() or tricks with pointers, but every one segfaults. I've also seen people saying that malloc() should be used, but I'm not sure of how I'd used it in a loop like this.
I will not claim to understand what it is that you're trying to do, but your code has two problems:
You're assigning a read-only string to Return; that string will be in your
binary's data section, which is read-only, and if you try to modify it you will get a segfault.
Your for loop is O(n^2), because strlen() is O(n)
There are several different ways of solving the "how to return a string" problem. You can, for example:
Use malloc() / calloc() to allocate a new string, as has been suggested
Use asprintf(), which is similar but gives you formatting if you need
Pass an output string (and its maximum size) as a parameter to the function
The first two require the calling function to free() the returned value. The third allows the caller to decide how to allocate the string (stack or heap), but requires some sort of contract about the minumum size needed for the output string.
In your code, when the function returns, then Return will be gone as well, so this behavior is undefined. It might work, but you should never rely on it.
Typically in C, you'd want to pass the "return" string as an argument instead, so that you don't have to free it all the time. Both require a local variable on the caller's side, but malloc'ing it will require an additional call to free the allocated memory and is also more expensive than simply passing a pointer to a local variable.
As for appending to the string, just use array notation (keep track of the current char/index) and don't forget to add a null character at the end.
Example:
int arg(char* ptr, char* S, int Num) {
int i, Spaces = 0, cur = 0;
for (i=0; i<strlen(S); i++) {
if (S[i] == ' ') {
Spaces++;
}
else if (Spaces == Num) {
ptr[cur++] = S[i]; // append char
}
else if (Spaces > Num) {
ptr[cur] = '\0'; // insert null char
return 0; // returns 0 on success
}
}
ptr[cur] = '\0'; // insert null char
return (cur > 0 ? 0 : -1); // returns 0 on success, -1 on error
}
Then invoke it like so:
char myArg[50];
if (arg(myArg, "this is an example", 3) == 0) {
printf("arg is %s\n", myArg);
} else {
// arg not found
}
Just make sure you don't overflow ptr (e.g.: by passing its size and adding a check in the function).
There are numbers of ways you could improve your code, but let's just start by making it meet the standard. ;-)
P.S.: Don't malloc unless you need to. And in that case you don't.
char * Return; //by the way horrible name for a variable.
Return = malloc(<some size>);
......
......
*(Return + index) = *(S+i);
You can't assign anything to a string literal such as "".
You may want to use your loop to determine the offsets of the start of the word in your string that you're looking for. Then find its length by continuing through the string until you encounter the end or another space. Then, you can malloc an array of chars with size equal to the size of the offset+1 (For the null terminator.) Finally, copy the substring into this new buffer and return it.
Also, as mentioned above, you may want to remove the strlen call from the loop - most compilers will optimize it out but it is indeed a linear operation for every character in the array, making the loop O(n**2).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *arg(const char *S, unsigned int Num) {
char *Return = "";
const char *top, *p;
unsigned int Spaces = 0;
int i = 0;
Return=(char*)malloc(sizeof(char));
*Return = '\0';
if(S == NULL || *S=='\0') return Return;
p=top=S;
while(Spaces != Num){
if(NULL!=(p=strchr(top, ' '))){
++Spaces;
top=++p;
} else {
break;
}
}
if(Spaces < Num) return Return;
if(NULL!=(p=strchr(top, ' '))){
int len = p - top;
Return=(char*)realloc(Return, sizeof(char)*(len+1));
strncpy(Return, top, len);
Return[len]='\0';
} else {
free(Return);
Return=strdup(top);
}
//printf("%s-\n", Return);
return Return;
}
int main(){
char *word;
word=arg("make a quick function", 2);//quick
printf("\"%s\"\n", word);
free(word);
return 0;
}

Resources