two strings should be different length but are counted as same length - c

I'm running into an issue with a pair of strings. Toward the bottom of my first function I test the length of both strings, and even though searchingForLength should be less than half the size of searchedLength, they are the same "length". What is going on here?
Here's the code:
#include <stdio.h>
#include <stdbool.h>
bool findString(const char searched[], const char searchingFor[]) {
int i, j, k = 0, searchedLength = sizeof(searched)/sizeof(searched[0]), searchingForLength = sizeof(searchingFor)/sizeof(searchingFor[0]);
bool in = false;
for (i = 0; i < searchedLength; i++) {
for (j = 0; j < searchingForLength; j++) {
if (searched[i] == searchingFor[j]) {
k++;
if (k == searchingForLength) {
in = true;
}
}
}
}
printf("%d\n", k);
printf("%d\n",searchingForLength);
printf("%d\n",searchedLength);
if (in == true) {
printf("Yes\n");
}
else {
printf("No\n");
}
return in;
}
int main (void) {
const char searched[] = { 'I', ' ', 'l', 'i', 'k', 'e', ' ', 'p', 'i', 'e' };
const char searchingFor[] = { 'l', 'i', 'k', 'e' };
findString(searched, searchingFor);
return 0;
}

Sizeof is evaluated at compile time, and in this case it will return the size of a pointer (char[] is more or less a char*). You should use strlen instead.
Oh and as it has been mentioned, you strings are not zero-terminated, so that won't really work either. You should define your strings as
const char blah[] = "whee"

The sizeof is an operator and it gives the size of the type of it's argument, which is not the length of a string.
For arrays it gives the size of the array in bytes, to calculate the length of a string you need strlen(), but none of your arrays are strings, and hence you can't use strlen(), they are not strings in a c string sense.
A string in c, is a sequence of non-nul bytes followed by a nul byte, your arrays don't have a terminating nul, so the str* functions can't handle them properly.
A simple implementation of strlen() would be
size_t strlen(const char *string)
{
size_t length;
length = 0;
while (*string++ != '\0')
length++;
return length;
}
as you can see, if there is no '\0' or nul byte1 in the data, the function will keep iterating beyond the end of the string, what happens after that is undefined.
1They are the same and their value is 0

Related

C - Ways to count array length

I need the length of an array. One way works perfectly, one gives the wrong answer, and one doesn't compile.
This doesn't compile:
size_t len = sizeof(array) / sizeof(array[0]);
This counts only first 4 letters:
size_t len = sizeof(array) / sizeof(char);
And len = 12 works.
I really don't understand this so some hint is greatly appreciated.
const char array[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', '\0'};
void count_chars(const char *array, unsigned int *counts)
{
size_t len = 12;
for(size_t i = 0; i < len; i++){
counts[(int)array[i]]++;
}
}
You cant determine the size of the passed array inside function. You need to pass size as an additional parameter.
const char array[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', 0};
void count_chars(const char *arr, unsigned int *counts, size_t size)
{
for(size_t i = 0; i < size; i++)
counts[(unsigned)arr[i]]++;
}
int main(void)
{
int cnt[sizeof(array[0]) * (1 << CHAR_BIT)];
count_chars(array, cnt, sizeof(array) / sizeof(array[0]));
}
You need to cast to unsigned (not int) because char values can be negative.
What you are trying to do is actually impossible in C. The general rule of thumb is to calculate the length of the array in the function where the array is declared and pass it to the function. This is due to the fact that C doesn't pass the entire array when calling a function but rather just the base address as a pointer variable. To breakdown your approaches and the reason they do/don't work are:
size_t len = sizeof(array) / sizeof(array[0]);
This the commonly accepted approach but the prerequisite is that array must be declared in the same scope not be a pointer.
size_t len = sizeof(array) / sizeof(char);
As array is pointer a type variable and therefore has the size 4(atleast on 32-bit machines) dividing by sizeof(char) is 1 resulting in the answer 4
size_t len = 12;
This works as it's hard coded.
An easy solution in your case could be use:
size_t len = strlen(array)
as mentioned assuming you can guarantee that the last element will be 0 or '\0'. In this situation you could also simply modify the looping condition to:
for(int i = 0; array[i] != 0; i++) {
...
}
Hope I could clarify your doubt
size_t len = sizeof(array) / sizeof(array[0]);
This is general approach for getting the length of an array. However, this will not work inside count_chars function because array is defined as local variable (a pointer) inside the API. And if it is the case, the result will be 13 (not 12 as you mentioned) because it count also the \0 at the end.
For string of characters, it is possible to use strlen. As in the question, you expected result = 12 so this might be your right solution. However, this will not work if there is some \0 value in the middle because it will find first string terminator (\0).
In C if you want to get length of Null Terminated Strings you have to check for NULL \0 and count characters.
Check here how strlen method works.
//Custom Strlen function.
size_t my_strlen(const char *str)
{
register const char *s;
for (s = str; *s; ++s);
return(s - str);
}
Strlen Source
To count length of Arrays (General) like Int,Float,Double you can use below method.
size_t int_arr_len = sizeof(int_arr) / sizeof(int_arr[0]);
size_t float_arr_len = sizeof(float_arr) / sizeof(float_arr[0]);
Full Source Code below
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char char_arr[] = {'t', 'h', 'i', 's', 'i', 's', 'm', 'y', 't', 'e', 'x', 't', 0}; // `\0` Null Terminated.
const int int_arr[] = {10, 20, 30, 40, 50};
const float float_arr[] = {1.5f, 2.5f, 3.5f, 4.5f, 5.5f};
//Custom Strlen function.
size_t my_strlen(const char *str)
{
register const char *s;
for (s = str; *s; ++s);
return(s - str);
}
int main()
{
//Array length for Strings(Char array. Null Terminated. `\0`)
size_t char_arr_len1 = strlen(char_arr);
size_t char_arr_len2 = my_strlen(char_arr);
//Array length for General arrays like Int,Float,Double...etc
size_t int_arr_len = sizeof(int_arr) / sizeof(int_arr[0]);
size_t float_arr_len = sizeof(float_arr) / sizeof(float_arr[0]);
//Print length of arrays.
printf("char_arr_len1: %zu\n", char_arr_len1);
printf("char_arr_len2: %zu\n", char_arr_len2);
printf("int_arr_len: %zu\n", int_arr_len);
printf("float_arr_len: %zu\n", float_arr_len);
return 0;
}

=CS50 PSET 2 CAESAR= How do I convert the key to digit? It gives me this error if I use atoi()

I'm having a problem with atoi() in the only_digits function. I asked on discord and they said that I am passing a char type arg to atoi() which doesn't work since atoi() only takes string or char * (array of char) as arguments. I don't get it. I'm confused with the difference of string and char. Aren't I passing argv[1] (which is a string) to only_digits? Which means inputKey is a string as well? So what do they mean that I am passing a char type arg to atoi()? How exactly do I make atoi() work? I'm stuck with this problem for 2 days now.
// Encrypts text using Caesar's cipher
// ci = (pi + k) % 26
#include <cs50.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
bool only_digits (string inputKey);
char rotate (char plaintext[], int key);
int main(int argc, string argv[])
{
string p;
// Make sure program was run with just one command-line argument
if (argc != 2)
{
printf("Enter exactly one input\n");
return 1;
}
// Make sure every character in argv[1] is a digit (DOESN'T WORK)
/*else if (only_digits(argv[1]))
{
printf("Usage: ./caesar key\n");
return 1;
}*/
else
{
p = get_string("plaintext: ");
}
// Convert argv[1] from a string to an int
int k = atoi(argv[1]);
char c[strlen(p) + 1];
// Convert ASCII range down to a value from 0 to 25
// For each character in the plaintext: (DOESN'T WORK)
for (int i = 0, n = strlen(p); i <= n; i++)
{
// Rotate the character if it's a letter // ci = (pi + k) % 26
if (isalpha(p[i]))
{
if (isupper(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
else if (islower(p[i]))
{
c[i] = ((p[i]) + k) % 26;
}
}
}
printf("ciphertext: %s\n", c);
}
// Function to encrypt plaintext
/*char rotate (char plaintext[], int key)
{
char c[strlen(plaintext) + 1];
return c;
}*/
// Function to check if key is a digit (DOESN'T WORK)
bool only_digits (string inputKey)
{
int flag = 0;
for (int i = 0, n = strlen(inputKey); i < n; i++)
{
// Converts string input to int
int response = atoi(inputKey[i]);
// Check if it is a digit
if (!(isdigit(response)))
{
flag++;
}
}
if (flag != 0)
{
return false;
}
else
{
return true;
}
}
Strings in C are defined as a sequence of nonzero bytes (characters), followed by a null-terminating byte:
char str[] = "hello"; /* in memory: { 'h', 'e', 'l', 'l', 'o', '\0' } */
atoi (ASCII to integer) expects a proper null-terminated string (char *). You can not pass it a single char.
int number = atoi("1672387");
isdigit expects a single character.
int is_true = isdigit('5');
In your program inputKey[i] is a single character. You can test it directly with isdigit, there is no need to convert it to an integer representation beforehand.
You can also simply return early if you encounter a non-digit character.
bool only_digits(string inputKey) {
for (size_t i = 0, length = strlen(inputKey); i < length; i++)
if (!isdigit(inputKey[i]))
return false;
return true;
}
Note: size_t is the return type of strlen, and the most appropriate type for indexing memory.

strlen() crashes when I call it

I am trying to write a simple piece of code that merges two strings together in even and odd indexes.
This is the code
void two_strings(char a[], char b[]) {
int counta = 0, countb = 0;
int lena = strlen(a);
int lenb = strlen(b);
int lenab = lena + lenb;
char ans[lenab];
for(int i = 0; i<strlen(ans); i++) {
if(i%2 == 0) {
ans[i] = a[counta];
counta++;
}
else {
ans[i] = b[countb];
countb++;
}
}
printf("%s\n", ans);
}
This is the main:
int main() {
char a[] = "hello";
char b[] = "bye";
two_strings(a, b);
return 0;
}
I have compiled it with -Wall and didn't get any warnings or errors, and I have tried it also with long instead of int just to check if that was the issue. when I run the code it doesn't get past the first strlen(a)
Strings in C are defined as a sequence of non-null bytes followed by a terminating null byte ('\0').
The following are equivalent strings
char one[] = "hello";
char two[] = { 'h', 'e', 'l', 'l', 'o', '\0' };
Both of these would have a string length of 5, and occupy 6 bytes of memory.
String handling functions in the Standard Library expect this null-terminating byte, and you will invoke Undefined Behavior by passing a non-null-terminated array to them. strlen and printf (with %s) are examples of these kinds of functions.
In your two_strings function you are not allocating enough memory to store the null-terminating byte. You also make no attempt to place this null-terminating byte in the array.
Allocate an additional byte for the null-terminating byte, and do not attempt to take the string length of an uninitialized array.
void two_strings(char a[], char b[]) {
/* ... */
size_t length = strlen(a) + strlen(b);
char string[length + 1];
for (size_t i = 0; i < length; i++) {
/* ... */
}
string[length] = '\0';
/* ... */
}
Also note that size_t is the correct type to use when dealing with memory indexing, and is the type returned by strlen.
As for your algorithm, in the event where your input strings differ in length you will attempt to continue indexing one of the strings after you have already reached its end.
You will either want to: only take the smaller string's length of characters from the larger string, stopping when the smaller string has been exhausted; or, append the remaining characters of the larger string to the result after the smaller string has been exhausted.
A quick example of the second approach:
#include <stdio.h>
#include <string.h>
void zip_strings(const char *a, const char *b) {
size_t combined_length = strlen(a) + strlen(b);
char joined_string[combined_length + 1];
for (size_t i = 0; i < combined_length; i++) {
const char **src = i & 1 ? &b : &a;
if (!**src)
src = &a;
if (!**src)
src = &b;
joined_string[i] = *((*src)++);
}
joined_string[combined_length] = '\0';
puts(joined_string);
}
int main(int argc, char **argv) {
if (argc > 2)
zip_strings(argv[1], argv[2]);
}
./a.out hello computer
hceolmlpouter

How to make a Sentence out of 2D char array using pointers

I am newbie at C so please try to be patient if I am not clear enough.
I have an assignment which I need to make a function that gets a squared char matrix and make a string out of it.
The function should return a pointer to a string eventually,
so that in main I can initialize a string with it and print it in the end.
(also i am restricted to use only pointers inside this function and not regular arrays syntax)
for example the matrix is:
R O M E
G O A L
H E A D
D E A D
and i want to make a sentence like that: "ROME GOAL HEAD DEAD".
I tried to make a for loop which runs only on the matrix rows so I could take each row and copy to a string which I already prepared before (with enough space in it) in the first row I used strcpy() and the other strcat().
Nothing happened.
Sorry for my english, and thanks.
char * makeString(char *smallMat, int rows, char *pStr ) {
int i;
char sentence[(rows * rows) + rows + rows];
pStr = &sentence;
for (i = 0; i < rows; ++i) {
if (i == 0) {
strcpy(sentence, *(smallMat + i));
}
else{
strcat(sentence, ' ' + *(smallMat + i));
}
}
return pStr;
}
As #anonmess pointed out, you cannot use strcpy() etc. for non-0-terminated character sequences. As you said yourself, the task is to use pointers. If you used strcpy() (and if it worked), you would work around the assignment ;)
Here is a full solution that does not use pStr.
#include <stdio.h> // printf()
#include <stdlib.h> // malloc()
static char smallMat[4][4] = {
{ 'R', 'O', 'M', 'E' },
{ 'G', 'O', 'A', 'L' },
{ 'H', 'E', 'A', 'D' },
{ 'D', 'E', 'A', 'D' }
};
char* makeString(char* smallMat, int rows) {
int currentRow, currentColumn;
/* space for all characters (rows * rows)
* + one character for each space + terminating '\0'. */
char* sentence = malloc((rows * rows) + rows);
char* p = sentence;
for (currentRow = 0; currentRow < rows; ++currentRow) {
for (currentColumn = 0; currentColumn < rows; ++currentColumn) {
*p++ = *(smallMat + (currentRow * rows) + currentColumn);
}
*p++ = ' ';
}
*--p = '\0'; /* replace the last space with terminating 0,
* so it can be printed. */
return sentence;
}
int main() {
char* output = makeString(smallMat, 4);
printf(output);
free(output);
return 0;
}
The easiest way to go about creating a sentence from your 2D array of SIZE rows and columns of characters is simply to create an array of SIZE * SIZE + SIZE characters to hold the sentence (SIZE * SIZE for each character, plus SIZE - 1 spaces, plus the nul-terminating character)
After declaring an array to hold your sentence, pass both the new array and your 2D array to your makestring() function and loop over each character in the 2D array, adding a space before each word (except for the 1st word) and finally nul-terminate your new array creating a C-string.
You cannot use strcpy (or any other function expecting a C-string) on the row of characters in your 2D array as the rows of characters in your 2D array are not nul-terminated strings. (your 2D array is just that, a 2D array of characters). You must loop over and assign each character to a position within your 1D array.
Putting it altogether, you could write makestring() similar to:
#define SIZE 4
char *makestring (char *str, char (*a)[SIZE])
{
char *p = str; /* a pointer to 1st character in str */
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = a[i][j]; /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to string (for convenient use in-line) */
}
(note: returning a pointer to the beginning of str would allow the function to be used in-line such as: printf ("str: '%s'\n", makestring (str, matrix)); As mentioned, this is just for convenience, you can make the function of type void as you are not allocating and have provided a pointer to an array that will be updated within the function and can be tested back in the caller before use.)
Adding a short test program, you could test your function as follows:
#include <stdio.h>
#define SIZE 4
char *makestring (char *str, char (*a)[SIZE])
{
char *p = str; /* a pointer to 1st character in str */
for (int i = 0; i < SIZE; i++) { /* for each row */
if (i) /* if row not 1st */
*p++ = ' '; /* add space */
for (int j = 0; j < SIZE; j++) /* for each char */
*p++ = a[i][j]; /* copy to str */
}
*p = 0; /* nul-terminate string */
return str; /* return pointer to string (for convenient use in-line) */
}
int main (void) {
char matrix[SIZE][SIZE] = { {'R','O','M','E'}, /* square 2D array */
{'G','O','A','L'},
{'H','E','A','D'},
{'D','E','A','D'} },
str[SIZE * SIZE + SIZE] = ""; /* array to hold sentence */
makestring (str, matrix); /* call makestring */
if (*str != 0) /* validate str not empty-string */
printf ("str: '%s'\n", str); /* output string */
}
Example Use/Output
Running the program would produce:
$ ./bin/makestring
str: 'ROME GOAL HEAD DEAD'
(note: single-quotes added around the string to affirmatively show the beginning and end of the string)
Look things over and let me know if you have further questions.

Trying to delete string characters

I'm trying to delete characters in a string by replacing them with empty quotes. It's giving me the following error message:
incompatible pointer to integer conversion assigning to
'char' from 'char [1]' [-Wint-conversion]
source[i] = "";
^ ~~
I'm getting the same error when I replace the empty string with a character and I thought this was the procedure for replacing array elements, so I'm not sure how to proceed.
Here's my code:
#include <stdio.h>
#include <string.h>
int removeString(char source[], int startIndex, int numberRemove) {
int i;
for (i = startIndex; i < startIndex + numberRemove; i++) {
printf ("%c", source[i]);
source[i] = "";
}
for (i = 0; i < strlen(source); i++) {
printf("%c\n", source[i]);
}
return 0;
}
int main (void) {
char text[] = { 'T', 'h', 'e', ' ', 'w', 'r', 'o', 'n', 'g', ' ', 's', 'o', 'n' };
removeString(text, 4, 6);
return 0;
}
You cannot assign "" to a char! "" is a char * (It's better to say an ASCII0 string).
I think you want insert a 0 code in the string! This is not a good choice because 0 indicates the end of an ASCII0 string.
You may substitute the char with a space:
source[i] = ' ';
But I think it's not what you want!
To take off the char from the string you have to move all chars after the char you want remove on the char to be deleted. ;)
If you want that an ASCII0 string is printed and managed as a void string
just put a 0 in the first byte!!!
source[0]=0;
or
*source=0;
Try using:
memset(source, 0, strlen(source));
This will set the entire string length to null terminate char. What you are doing above:
source[i] = "";
is an error for several reasons:
When you set a char in C, you use single quotations: ''
empty and null terminate char are not the same.
Solved it. Basically I'm looping over the string and printing out the chars if they are within the specified value range.
#include <stdio.h>
#include <string.h>
int removeString(char source[], int startIndex, int numberRemove) {
int i;
for (i = 0; i < strlen(source); i++) {
if (i < startIndex || i >= startIndex + numberRemove) {
printf("%c", source[i]);
}
}
return 0;
}
int main (void) {
char text[] = { 'T', 'h', 'e', ' ', 'w', 'r', 'o', 'n', 'g', ' ', 's', 'o', 'n', '\0' };
removeString(text, 4, 6);
return 0;
}

Resources