I am trying to compare strings received from the command line arguments without using the string library. I have created a function to compare char*'s and it works for strings I create in my program, but not on strings passed in the command line. Here is the code for reference.
#include <stdio.h>
int comparestr(char* a, char* b) {
printf("string 1 = %s, string 2 = %s\n", a, b);
int len_a =0, len_b=0;
while(*a) {
len_a++;
a++;
}
while(*b) {
len_b++;
b++;
}
printf("len a = %d, len b = %d\n", len_a, len_b);
if (len_a == len_b) {
for(int i=0; i<len_a; i++) {
if(*(a+i) != *(b+i)) {
return 0;
}
}
return 1;
}
else
return 0;
}
int main(int argc, char**argv) {
char* str1 = "hello";
char* str2 = "hello";
if(comparestr(str1,str2))
printf("Same string.\n");
else
printf("Different strings.\n");
if(comparestr(*(argv+1),"hell"))
printf("Same cl string.\n");
else
printf("Different cl strings.\n");
return 0;
}
Here is an example of the output.
./a.out hell hell
string 1 = hello, string 2 = hello
len a = 5, len b = 5
Same string.
string 1 = hell, string 2 = hell
len a = 4, len b = 4
Different cl strings.
The issue with your code is that you change the pointer by incrementing it when you try to get the length of the strings. Once you change the pointers, the pointers will not point to the base of your strings.
Instead of changing your pointer, make a copy of it, and use the copy instead to calculate the length of the string, that way you don't lose the base address of your strings.
New code with changes.
//Copy of the pointer, to change this instead and keep the original pointer address
char* ptr_a = a;
char* ptr_b = b;
int len_a =0, len_b=0;
while(*ptr_a) {
len_a++;
ptr_a++;
}
while(*ptr_b) {
len_b++;
ptr_b++;
}
The whole code.
#include <stdio.h>
int comparestr(char* a, char* b) {
printf("string 1 = %s, string 2 = %s\n", a, b);
//Copy of the pointer, to change this instead and keep the original pointer address
char* ptr_a = a;
char* ptr_b = b;
int len_a =0, len_b=0;
while(*ptr_a) {
len_a++;
ptr_a++;
}
while(*ptr_b) {
len_b++;
ptr_b++;
}
printf("len a = %d, len b = %d\n", len_a, len_b);
if (len_a == len_b) {
for(int i=0; i<len_a; i++) {
if(*(a+i) != *(b+i)) {
return 0;
}
}
return 1;
}
else
return 0;
}
int main(int argc, char**argv) {
char* str1 = "hello";
char* str2 = "hello";
if(comparestr(str1,str2))
printf("Same string.\n");
else
printf("Different strings.\n");
if(comparestr(*(argv+1),"hell"))
printf("Same cl string.\n");
else
printf("Different cl strings.\n");
return 0;
}
New Output
Command-line arguments: hell hell
string 1 = hello, string 2 = hello
len a = 5, len b = 5
Same string.
string 1 = hell, string 2 = hell
len a = 4, len b = 4
Same cl string.
Related
I am attempting to write the substitution program here https://cs50.harvard.edu/x/2022/psets/2/substitution/
here is my code:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
int main(int argc, string argv[1])
{
if (argc > 2 || argc < 2){
printf("Plz 1 word in command \n");
return 1;
}
int sum = 0;
string arg1 = argv[1];
//test
for (int i = 0; i < strlen(arg1); i++){
if (isalpha(arg1[i]) == 0){
printf("plz only alphabet character \n");
return 1;
}}
// convert all key to upper
for (int i = 0; i < strlen(arg1); i++){
arg1[i] = toupper(arg1[i]);
}
for (int i = 0; i < strlen(arg1); i++){
sum = sum + (int)(arg1[i]);
}
if (strlen(arg1) != 26){
printf("Plz input 26 char \n");
return 1;
} else if (sum != 2015){printf("no oveerlapping letter plz \n");
return 1; }
//test finish
string al = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
string pt = get_string("plaintext: ");
char pt1[strlen(pt)];
char cp[strlen(pt)];
// all plain text to upper
for (int i = 0; i < strlen(pt); i++){
pt1[i]=toupper(pt[i]);
}
//scan
for (int a = 0; a < strlen(pt); a++){
char b = pt1[a];
for (int i = 0; i < strlen(al); i++){
if ( al[i] == b){
cp[a] = arg1[i];
break;
} else {
cp[a] = b;
}
}
//case preserve
if (islower(pt[a])){
cp[a] = tolower(cp[a]);
}}
printf("ciphertext: %s \n", cp);
return 0;
}
when i type in the key YTNSHKVEFXRBAUQZCLWDMIPGJO and then type "hello!1 lmao" as plaintext, here is what i receive
substitution/ $ ./substitution YTNSHKVEFXRBAUQZCLWDMIPGJO
plaintext: hello!1 lmao
ciphertext: ehbbq!1 bayq�
it should only show ehbbq!1 bayq but it is showing more letter than i intended,
there might be other letter or simbol after "bayq", can someone explain to me what is going on and why there are additional text in my output?
You need a null terminatig character (usually it is character having integer value 0) to terminate the string
size_t a;
for (a = 0; a < strlen(pt); a++)
{
char b = pt1[a];
for (int i = 0; i < strlen(al); i++)
{
if ( al[i] == b)
{
cp[a] = arg1[i];
break;
} else {
cp[a] = b;
}
}
//case preserve
if (islower((unsigned char)pt[a]))
{
cp[a] = tolower((unsigned char)cp[a]);
}
}
cp[a] = 0;
you need to pass unsigned char to functions like tolower. I did not analyze the logic of your code as it is your home work.
Also cp is too short, it has to be char cp[strlen(pt) + 1];
Your char arrays as declared are too short to handle copies of the data, due to the need for a null-terminator att the end.
char pt1[strlen(pt)];
char cp[strlen(pt)];
Rather you need to do:
char pt1[strlen(pt) + 1];
char cp[strlen(pt) + 1];
However, the other approach would be to simply use strdup to dynamically allocate sufficient storage and copy the data.
char pt1 = strdup(pt);
char cp = strdup(pt);
Of course, any function that returns dynamically allocated memory (likely including cs50's get_string) means you should remember to free that memory. And ensure it actually succeeded.
I'm having issues getting the desired behaviour out of my code. I'm new to the C language (although I usually program in C++ so I'm sort of familiar), and I'm unsure where to go with my issue. In the below code, when attempting to populate the 2 strings with the contents of the "input" string passed to the function, the result is that the memory locations are passed to the 2 strings, meaning when I perform modifications on the individual strings, the original data is edited... I want to have it such that the initial data is copied to the new memory locations allocated to the new strings.
bool interpretInput(char *input)
{
char *name = malloc(MAX_NAME_SIZE / 2);
char *surname = malloc(MAX_NAME_SIZE / 2);
if (name == NULL | surname == NULL)
{
return 1;
}
int length = (int) strlen(input);
if ((length > 0) && (input[length - 1] == '\n')) input[length - 1] = '\0';
if (surname = strpbrk(input, " "))
{
int sLength = (int) strlen(surname);
for (int i = 0; i < sLength; i++)
{
surname[i] = surname[i + 1];
}
length = (int) strlen(input);
for (int i = 0; i <= length - sLength; i++)
{
name[i] = input[i];
}
length = (int) strlen(name);
sLength = (int) strlen(surname);
printf("Name: %s length: %d \n", name, length);
printf("Surname: %s length: %d \n", surname, sLength);
}
else
{
printf("Name length: %d", length);
}
return 0;
}
EDIT: I, effectively, want to populate one array with the values at each increment of another array, without using strcpy.
I think you want strcpy(char* dest, char* src). Dereferencing a char* will simply yield you the first char in the string.
#include <stdio.h>
int main()
{
char* test = "hello world";
char* test2 = malloc(11*sizeof(char));
strcpy(test2, test);
printf("%s\n", test);
printf("%s\n", test2);
test2[5] = '_';
printf("%s\n", test);
printf("%s\n", test2);
printf("%c\n", *test);
free(test2);
}
spits out
hello world
hello world
hello world
hello_world
h
I have an array of strings and am trying to reverse each string in the array to see if that string is a palindrome. I am using a for loop to increment an int i (the index). However after the I call the reverse function, the value of i becomes some really large number and I cant figure out why this is happening.
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source);
int main() {
const char *strs[] = {
"racecar",
"radar",
"hello",
"world"
};
int i;
char res[] = "";
for (i = 0; i < strlen(*strs); i++) {
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome");
} else {
printf("Not a palindrome");
}
}
return 0;
}
void revString(char *dest, const char *source) {
printf("%s\n", source);
int len = strlen(source);
printf("%d\n", len);
const char *p;
char s;
for (p = (source + (len - 1)); p >= source; p--) {
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
This is the output showing the value of i before and after the revString function is called.
i is 0
i is now 1667588961
Illegal instruction: 4
There are multiple problems in your code:
You pass a destination array char res[] = ""; that is much too small for the strings you want to reverse. It's size is 1. This causes buffer overflow, resulting in undefined behavior.
Use char res[20]; instead.
You enumerate the array of string with an incorrect upper bound. Use this instead:
for (i = 0; i < sizeof(strs) / sizeof(*strs); i++)
The termination test for the loop in revString() is incorrect too: decrementing p when is equal to source has undefined behavior, although it is unlikely to have an consequences. You can simplify this function this way:
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
Here is the resulting code:
#include <stdio.h>
#include <string.h>
void revString(char *dest, const char *source) {
size_t len = strlen(source);
for (size_t i = 0; i < len; i++) {
dest[i] = source[len - i - 1];
}
dest[len] = '\0';
}
int main(void) {
const char *strs[] = { "racecar", "radar", "hello", "world" };
char res[20];
for (size_t i = 0; i < sizeof(strs) / sizeof(*strs); i++) {
revString(res, strs[i]);
//comparing string and reversed string
if (strcmp(res, strs[i]) == 0) {
printf("Is a palindrome\n");
} else {
printf("Not a palindrome\n");
}
}
return 0;
}
Here is Final Code with some change
#include <stdio.h>
#include <string.h>
void revString(char* dest, const char* source);
int main(){
const char* strs[] = {
"racecar",
"radar",
"hello",
"world"
};
static int i;
char res[] = "";
int length = (int) sizeof(strs)/sizeof(char*);
for(i = 0; i < length; i++)
{
printf("i is %d\n", i);
revString(&res[0], strs[i]); //reversing string
printf("i is now %d\n", i);
//comparing string and reversed string
if(strcmp(res, strs[i]) == 0){
printf("Is a palindrome");
}else{
printf("Not a palindrome");
}
}
return 0;
}
void revString(char* dest, const char* source){
printf("%s\n", source);
int len = (int) strlen(source);
printf("%d\n", len);
const char* p;
char s;
for(p = (source + (len - 1)); p >= source; p--){
s = *p;
*(dest) = s;
dest += 1;
}
*dest = '\0';
}
Change 1 :-
int i; to static int i; (Reason:- i is local variable you are calling
function so when function call the value of i will remove and after
that it will assign garbage value.)
change 2 :-
strlen(*strs) to length of array (because strlen(*strs) will give the
length of first string)
I have written a function that uses the strstr() function to determine if string2 has any matches in string1. This works fine (I also convert both strings to lower case so that I can do a case-insensitive match.). However, strstr() only finds the first time the match occurs. Is there a way to use it to find each time a match occurs? For example:
string1[] = "ABCDEFABC";
string2[] = "ABC";
Would return 0 as a match is found in position 0, and 6 as it's found again in position 6?
Here's the original function as written (including call to function in main):
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *strstrnc(const char *str1, const char *str2);
int main()
{
char buf1[80],buf2[80];
printf("Enter the first string to be compared: ");
gets(buf1);
printf("Enter the second string to be compared: ");
gets(buf2);
strstrnc(buf1,buf2);
return 0;
}
char *strstrnc(const char *buf1, const char *buf2)
{
char *p1, *ptr1, *p2, *ptr2, *loc;
int ctr;
ptr1 = malloc(80 * sizeof(char));
ptr2 = malloc(80 * sizeof(char));
p1 = ptr1;
p2 = ptr2;
for (ctr = 0; ctr < strlen(buf1);ctr++)
{
*p1++ = tolower(buf1[ctr]);
}
*p1 = '\0';
for (ctr = 0; ctr < strlen(buf2);ctr++)
{
*p2++ = tolower(buf2[ctr]);
}
*p2 = '\0';
printf("The new first string is %s.\n", ptr1);
printf("The new first string is %s.\n", ptr2);
loc = strstr(ptr1,ptr2);
if (loc == NULL)
{
printf("No match was found!\n");
}
else
{
printf("%s was found at position %ld.\n", ptr2, loc-ptr1);
}
return loc;
}
Given
char string1[] = "ABCDEFABC";
char string2[] = "ABC";
strstr(string1, string2) will return a pointer to the first element of string1.
Would return 0 as a match is found in position 0, and 6 as it's found again in position 6?
In order to check for multiple occurrences of string2 in string1, you'll have to call strstr multiple times with an offset from string1. E.g.
char* found = strstr(string1, string2);
while ( found != NULL )
{
// Search for string2 after applying an offset.
int offset = 1;
found = strstr(found+offset, string2);
}
I think this is what you need:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(void){
char string1[] = "ABCDABCEFABC";
char string2[] = "ABC";
char *s1, *s2, *s3;
size_t lenstring1 = strlen(string1);
size_t lenstring2 = strlen(string2);
if (lenstring2 < 1){
printf("There is no substring found"); /* or what ever */
exit(1);
}
size_t i=0,j=0;
int found=0;
s1 = string1;
s2 = string2;
for(i = 0; i < lenstring1; i++){
if(*s1 == *s2){
s3 = s1;
for(j = 0;j < lenstring2;j++){
if(*s3 == *s2){
s3++;s2++;
}else{
break;
}
}
s2 = string2;
if(j == strlen(string2)){
found = 1;
printf("%s found at index : %zu\n",string2,i+1);
}
}
s1++;
}
if(found == 0){
printf("No match Found");
}
return 0;
}
Output:
ABC found at index : 1
ABC found at index : 5
ABC found at index : 10
If the string2 is empty you will get:
There is no substring found
I clearly am doing something wrong but, for the life of me, can't figure out what.
int main(int argc, char *argv[])
{
int done=0;
int end=0;
int didswap=0;
char *temp[2] = {0};
int i;
int x;
printf("This function Bubble sorts the Flintstones in alphabetical order!\n");
printf("The Flintstones names are:\nFred\nBarney\nWilma\nPebbles\nDino\n");
char *names[5] = {0};
names [0] = "Fred";
names [1] = "Barney";
names [2] = "Wilma";
names [3] = "Pebbles";
names [4] = "Dino";
while(end == 0)
{
for(i=0;i<4;i++)
{
if (strcmp(names[i],names[i+1])>0)
{
strcpy(temp[0],names[i]);
strcpy(temp[1],names[i+1]);
strcpy(names[i],temp[1]);
strcpy(names[i+1],temp[0]);
didswap = 1;
}
else
{
didswap = 0;
}
done = done+didswap;
}
if (done == 0)
end = 1;
else
done = 0;
}
printf("When alphabetized they are:\n");
for (i = 0; i < 5; i++)
{
printf("%s \n", names[i]);
}
system("PAUSE");
return EXIT_SUCCESS;
}
You have an array of string literals. These may be held in read only memory so you can't change their content. You can however change the order you store pointers to them in names by replacing
strcpy(temp[0],names[i]);
strcpy(temp[1],names[i+1]);
strcpy(names[i],temp[1]);
strcpy(names[i+1],temp[0]);
with
const char* tmp = names[i];
names[i] = names[i+1];
names[i+1] = tmp;
strcpy(temp[0],names[i]);
strcpy(temp[1],names[i+1]);
strcpy(names[i],temp[1]);
strcpy(names[i+1],temp[0])
names strings are string literals and string literals are immutable in C. Attempting to modifiy a string literal invokes undefined behavior.