I'm a beginner in programming so I've been making some mini projects.
I am trying to make a code that takes a string and returns one in which each character is repeated once and I'm getting an error and these signs (╠╠╠╠╠╠╠╠).
Where am I going wrong?
char str[20], fin[40];
int i, j=0;
gets(str);
while (str[j] != '\0'){
j++;
}
for (i = 0; i < j; i++){
fin[i*2-1] = str[i];
fin[i*2] = str[i];
}
printf("%s\n", fin);
return 0;
C does not have strings. Strings, in C, are a convention used by the compiler and the programmer and the Standard Library (and every library ever written). If you break the convention strings no longer "work" even though your code may be correct C code.
Depending on context, a string is a [part of an] array of char that contains a zero byte, or a pointer to such an array, like
char text[3] = {'h', 'i', '\0'}; // text is an array that contains the string "hi"
char *ptr = text; // ptr points to the string "hi"
When you build your string character-by-character, remember the array elements start as garbage
char fin[20]; // fin is an array of 20 characters.
// It is capable of holding string of up to 19 characters length
// and the respective terminator
fin[0] = 'C'; // fin (the whole array) is not a string
fin[1] = '\0'; // fin now is the string "C" with the proper terminator (and a bunch of unused elements
fin[1] = ' '; // replaced the terminator with a space
// fin is no longer a string
fin[2] = 'i';
fin[3] = 's'; // "C is############garbage########..." not a string
fin[4] = ' ';
fin[5] = 'f';
fin[6] = 'u';
fin[7] = 'n'; // "C is fun########garbage########..." not a string
fin[8] = '.'; // "C is fun.#######garbage########..." not a string
fin[9] = '\0'; // "C is fun." <== definitely a string
That's what you need to do. Add a '\0' at the end.
Related
I'm trying to write a function to split a string (not use strtok) to learn how it works. I've come up with the following so far:
char ** split_string(char * string, char sep) {
// Allow single separators only for now
// get length of the split string array
int array_length = 0;
char c;
for (int i=0; (c=string[i]) != 0; i++)
if (c == sep) array_length ++;
// allocate the array
char * array[array_length + 1];
array[array_length] = '\0';
// add the strings to the array
for (int i=0, word=0; (c=string[i]) != 0;) {
if (c == sep) {
i=0;
word ++;
} else {
array[i][word] = c;
i++;
}
}
return array;
}
This is my first time working with a pointer to a pointer (a list of strings), so I'm a bit unclear how to do this, as you can probably tell from the above function.
How would this be properly done? Specifically, is the return type correct? How would you add the \0 to the end of the array?
the one mistake you are making is not allocating space for the words to be copied. You must explicitly allocate space for the words in the destination array before copying. Following program achieves what's intended. To know the number of words, declare array_length to be a global variable, so that you can use that in the function where split_string was called.
int array_length=0;
char** split_string(char* str, char sep){
for(int i = 0;str[i] != '\0';++i){
if(str[i] == sep) ++array_length;
char** str_arr = (char**)malloc(sizeof(char*) * (array_length+1));
for(int i=0, j, k = 0; str[i] != '\0'; ++k){ // k is used to index the destination array for the extracted word
for(j = i; str[j] != sep && str[j] != '\0'; ++j); // from the current character, find the position of the next separator
str_arr[k] = (char*)malloc((j-i+2)*sizeof(char)); // Allocate as many chars in the heap and make str_arr[k] pointer point to it
strncpy(str_arr[k], str+i, j-i); // copy the word to the allocated space
i=j+1; // move the array iterator to the next non-sep character
}
return str_arr;
}
If you don't want to use malloc explicitly, you can also use library function strndup which takes the pointer to the start character of the source string and number of characters to be copied as input and does the memory allocation, copies the word and returns the pointer to the allocated space. so two of the lines in the function
str_arr[k] = (char*)malloc((j-i+2)*sizeof(char)); // Allocate as many chars in the heap and make str_arr[k] pointer point to it
strncpy(str_arr[k], str+i, j-i);
can be replaced by a single line as-
str_arr[k] = strndup(str+i, j-i);
But I would recommend using the first method as a beginner for better understanding and debugging.
Note: The above program works only for single delimiter between words, if there is an occurrence of multiple consecutive delimiters between words, you will have to tweak the program a bit in order to get it working.
I am working on a Caesar cipher and I am trying to save the characters of my cipher key in an array based on the ascii of the letter is supposed to represent. So if my cipher char key[] = "codezyxwvutsrqpnmlkjihgfba"
The first char in the array (c) is supposed to represent the letter a, whose ascii num is 97. So I want to store c in the array in the 97th spot. Everytime I try to this the array turns out empty.
char key[] = {"codezyxwvutsrqpnmlkjihgfba"};
char alphabet[] = {"abcdefghijklmnopqrstuvwxyz"};
char answerKey[200] = "";
for (int i = 0; key[i] != '\0'; i++) {
answerKey[(int) alphabet[i]] = key[i];
}
for (int i = 0; answerKey[i] != '\0'; i++) {
printf("%c", answerKey[i]);
}
Since the answerkey array has values only in the range of 97 - 122 assuming you are only using lower alphabet the other elements of the arrays are garbage.
Just change the print for loop to iterate from 97 to 122 and you get what you want.
char key[] = {"codezyxwvutsrqpnmlkjihgfba"};
char alphabet[] = {"abcdefghijklmnopqrstuvwxyz"};
char answerKey[200]="";
for (int i = 0; key[i] != '\0'; i++) {
printf("%c",alphabet[i]);
answerKey[(int) alphabet[i]] = key[i];
printf("%c",answerKey[(int)alphabet[i]]);
}
printf("\n");
int i=0;
for (i = 97;i<=122; i++)
{
printf("%c", answerKey[i]);
}
You are starting your printing of the answerKey[] array at the first element and telling it to stop as soon as it hits '\0'. I don't believe answerKey[0] should ever not be '\0' since none of the printable ascii characters are 0. I would expect your answerKey[] array to be empty except between elements 97-122, so if your cipher will be used only for lowercase alphabetical characters, perhaps only look in that part of the array.
Alternatively, you could make your answerKey[] array only hold enough space to fit your cipher by subtracting 'a' from the element address as you're placing it. Something like this might do the trick:
char answerKey[27] = "";
for (int i = 0; key[i] !='\0'; i++) {
answerKey[(int) alphabet[i] - 'a'] = key[i];
}
In C, you can convert a char to an int by simply preforming a cast.
In the memory, when you have a char 'a', the value 97 is saved. When you use a char, it is just the way you understand what is written in the memory. you can just treat this memory as an int, and get the value which is stored over there.
For example:
char c = 'a';
printf("char is %c, int is %d", c, (int)(c));
// Output would be:
// char is a, int is 97
For further information, read: How are different types stored in memory
Since I don't really understand the overall issue I am having, it's become very difficult to debug.
char *o_key_pad = (char*)malloc(SHA256_DIGEST_LENGTH*sizeof(char));
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++){
o_key_pad[i] = 'a';
}
printf("%s\n", o_key_pad);
char *i_key_pad = (char*)malloc(SHA256_DIGEST_LENGTH*sizeof(char));
for(int i = 0; i < SHA256_DIGEST_LENGTH; i++){
i_key_pad[i] = 'b';
}
printf("%s\n", o_key_pad);
printf("%s\n", i_key_pad);
And i obtain outputs:
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
Why does the array 'o_key_pad' get extended to include whatever i put in array 'i_key_pad', seems like some sort of memory issue?
Note: I understand that it can be done more effectively but to show my point more clearly I have laid it out like this.
printf doesn't know where to stop unless you properly null-terminate your strings. C-style strings are as follows (the following two lines are equivalent; writing a string in quotes [a "string literal"] automatically creates a null-terminated character array):
char str[] = "hello world";
char str2[] = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '\0' };
This is what your code should look like:
int i;
char *o_key_pad = malloc(SHA256_DIGEST_LENGTH * sizeof (char) + 1);
for (i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
o_key_pad[i] = 'a';
}
o_key_pad[i] = '\0';
printf("%s\n", o_key_pad);
char *i_key_pad = malloc(SHA256_DIGEST_LENGTH * sizeof (char) + 1);
for (i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
i_key_pad[i] = 'b';
}
i_key_pad[i] = '\0';
printf("%s\n", o_key_pad);
printf("%s\n", i_key_pad);
/* Don't forget to free when done. */
free(o_key_pad);
free(i_key pad);
You have char arrays, but they do not have room for a string terminator, and in fact you do not append one. The contents are not, therefore, proper C strings. When you lie to printf() about that, anything can happen, but in practice, printing beyond the intended bounds of your data is a likely outcome.
If you do not want to add a terminator, then you could put a maximum field width into your format:
printf("%.32s\n", o_key_pad);
, or alternatively
printf("%.*s\n", SHA256_DIGEST_LENGTH, o_key_pad);
if you don't want to hardcode the field width directly into the format.
Your strings are not NULL-terminated, resulting in undefined behavior when passed to printf. You could either allocate one more byte and add a NULL character, or specify a maximum field width for your string.
This question already has answers here:
Strings without a '\0' char?
(6 answers)
Closed 8 years ago.
so i've made a 'guess_the_word' game in c that has a secret word with '-' and'' and whenever you find a correct character this character substitutes '-' or ''.However it seems that the secret word is not printed properly..although the first time it seemed to work.When i used a word with 2 consecutive same characters this problem appeared and then for every word i used.
int sel_size, i;
char select_word[] = "football"; /* the word we are searching*/
sel_size = strlen(select_word);
char secret_word[sel_size];
for (i = 0; i < sel_size; i += 2)
{
secret_word[i] = '_';
}
for (i = 1; i < sel_size; i += 2)
{
secret_word[i] = '-';
}
printf("player 2 the secret word is now %s\n", secret_word);/* it should print "_-_-_-_-" but it prints somthing like this"_-_-_-_-0²#*" */
Strings in C are character arrays terminated by the character '\0'. You never do this to secret_word, so printing it will invoke undefined behavior.
You need to allow for the terminator in the array size:
const size_t sel_size = strlen(select_word);
char secret_word[sel_size + 1]; /* Add 1 to fit the terminator. */
Then after initializing the characters, terminate the string:
secret_word[sel_size] = '\0';
Also, that business of incrementing i by 2 is also wrong, that will exhaust the array too quickly and lead to undefined behavior as you step outside the array. Don't do that. Just do:
memset(secret_word, '_', sel_size);
secret_word[sel_size] = '\0';
UPDATE: Ah, you want underscores separated by dashes. Then you need:
char secret_word[2 * sel_size];
for(size_t i = 0; i < sel_size; ++i)
{
secret_word[2 * i] = '_';
secret_word[2 * i + 1] = '-';
}
secret_word[2 * sel_size - 1] = '\0';
The above can be expressed more succinctly using pointers, but that might be considered more advanced, so indexing it is.
I have a few questions regarding array of strings in C.
I have an array char *string. I have a char *string and then I split every 4 characters in a array of strings called sep_str. So for example if char *string = 'The sum';, then char **sep_str is:
0: |_| --> "The "
1: |_| --> "Sum"
My first question is, in an array of strings in C (so array of array of chars), will there be a null terminating character at the end of each sep_str[i], or just at the last position of sep_str? Here is how I copy string into an array of strings:
for (int i = 0; i < str_length; i++) {
sep_str[i/4][i%4] = *ptr;
ptr++;
}
My second question is, how would I reverse the elements of each string in sep_str? Here's how I did it, but I feel like it is stepping out of the array of the substring. (so out of the element of the sep_str):
// Reverse each element in the array
char temp;
for (int i = 0; i < num_strs; i++) {
for (int j = 0, k = 4; j < k; j++, k--) {
temp = sep_str[i][j];
sep_str[i][j] = sep_str[i][k];
sep_str[i][k] = temp;
}
}
The copy of the strings sounds good to me. Since each string has always 4 chars, you can avoid the null terminator \0. Alternatively you need to declare sep_str as a 5x(lenght/4) matrix, to store the \0 char at the end of each string.
To reverse a string you need to iterate from the start to the middle of the string, replacing the i-th char with the length-i-1-th. You need to replace the inner for replacing k=3 to k=2.
You also need to take care of the last string, since the lenght might not be multiple of four.
char temp;
for (int i = 0; i < (num_strs - 1); i++) {
for (int j = 0, k = 3; j < k; j++, k--) {
temp = sep_str[i][j];
sep_str[i][j] = sep_str[i][k];
sep_str[i][k] = temp;
}
}
if (num_strs > 0) {
for (int j = 0, k = strlen(sep_str[i]) - 1; j < k; j++, k--) {
temp = sep_str[i][j];
sep_str[i][j] = sep_str[i][k];
sep_str[i][k] = temp;
}
}
In a C string, there will be only one termination character. But if you need to tokenize the strings, then each string must be null terminated.
But before that -
char *string = "The sum"; // should be const char* string = "The sum";
String literal in the above case resides in read only location and cannot be modified. If you need to modify, then
char string[] = "The sum";
If you don't have the terminating character in your strings then yes, you will be outside the bounds of the array since you are accessing sep_str[i][4], which is not a valid location:
sep_str[0] = 'T'
sep_str[1] = 'h'
sep_str[2] = 'e'
sep_str[3] = ' '
However, I doubt that you want to have the null character at the beginning of your string, so you need k=3 in your for loop, not k=4.
My first question is, in an array of strings in C (so array of array of chars), will there be a null terminating character at the end of each sep_str[i], or just at the last position of sep_str?
Only at the end, but if you want to treat each individual chunk as its own string, you'll need to add the \0 yourself.
My second question is, how would I reverse the elements of each string in sep_str?
You could do it with pointers...
char temp;
// Point to start of string, `str` will decay to first memory position.
char *start = str;
// Point to the end of the string. You will need to `#include <string.h>`
// for `strlen()`. Otherwise, write a `while` loop that goes until `\0` to find
// the last position.
char *end = &str[strlen(str) - 1];
// Do until we hit the middle of the string.
while (start < end) {
// Need a temp char, no parallel assignment in C.
temp = str[start];
// Swap chars.
str[start++] = str[end];
str[end--] = str[temp];
}
Assuming str is your string.