Why C dosen't split correctly arrays? - c

I have an array of 64 characters, which I need to divide into two parts, the left part of 32 characters and the right part, also 32 characters.
char *IP_M; // 64 characters array
char L[32]; // left part
char R[32]; // right part
The IP_M array is filled in as follow:
char *start_inital_permutation(const char *input) {
char *output = malloc(64 * sizeof(char));
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
output[i * 8 + j] = input[IP[i][j] - 1];
}
}
return output;
}
...
IP_M = start_inital_permutation(M);
where M is also a 64 characters string. With the following method I tried to fill the other two array (L, R) by spliting the IP_M.
void fill_LR() {
for (int i = 0; i < 32; i++) {
L[i] = IP_M[i];
R[i] = IP_M[i + 32];
}
}
but when I run the following instructions:
printf("IP_M: %s\n", IP_M);
printf("L: %s\n", L);
printf("R: %s\n", R);
the output is:
IP_M: 1100110000000000110011001111111111110000101010101111000010101010
L: 1100110000000000110011001111111111110000101010101111000010101010
R: 11110000101010101111000010101010
I can't get out of this situation, can someone help me please?
*EDIT: also tried the memcpy() method but it still not work!
Here is the Project if someone want to see it:
https://github.com/ionutbogdandonici/DES_C.git

Strings in C are \0 terminated. So the print function will print the string until it reaches the \0 character.
Assign space for null:
char L[33]; // left part
char R[33]; // right part
Add null terminator:
void fill_LR() {
for (int i = 0; i < 32; i++) {
L[i] = IP_M[i];
R[i] = IP_M[i + 32];
}
L[32] = 0;
R[32] = 0;
}

output[i * 8 + j] = input[IP[i][j] - 1]; is gibberish.
Strings in C are null terminated but you never allocate space for a null terminator anywhere, nor do you null terminate your strings.
Don't use global variables.
I was able to salvage your program like this:
#include <stdio.h>
#include <stdlib.h>
char *start_inital_permutation(const char *input) {
size_t count=0;
char *output = malloc(64 * sizeof(char) + 1);
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
output[i * 8 + j] = input[count++];
}
}
output[64] = '\0';
return output;
}
int main()
{
const char input[] = "1100110000000000110011001111111111110000101010101111000010101010";
char *IP_M = start_inital_permutation(input);
char L[32+1]; // left part
char R[32+1]; // right part
for (int i = 0; i < 32; i++) {
L[i] = IP_M[i];
R[i] = IP_M[i + 32];
}
L[32] = '\0';
R[32] = '\0';
printf("IP_M: %s\n", IP_M);
printf("L: %s\n", L);
printf("R: %s\n", R);
}
However, there's no apparent reason why you need to do the middle step with the 64 characters array. You could as well put that one in a union and save the copy (although then the individual left/right strings won't be null terminated). Example:
#include <stdio.h>
#include <stdlib.h>
typedef union
{
char data [64+1];
struct
{
char left[32];
char right[32];
char zero;
};
} ip_t;
ip_t *start_inital_permutation(const char *input) {
size_t count=0;
ip_t* obj = malloc(sizeof(ip_t));
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
obj->data[i * 8 + j] = input[count++];
}
}
obj->data[64] = '\0';
return obj;
}
int main()
{
const char input[] = "1100110000000000110011001111111111110000101010101111000010101010";
ip_t *IP_M = start_inital_permutation(input);
printf("IP_M: %s\n", IP_M->data);
printf("L: %.32s\n", IP_M->left);
printf("R: %.32s\n", IP_M->right);
}

Using printf with "%s" assumes the value is a zero terminated string (AKA NULL terminated string).
I.e. a pointer to a sequence of chars, ending with a \0 char.
In your case when printf attempts to print L it prints char, and after the 32 chars that belong to L it continues. It happened to be that R is following L in memory, and so the content of R is also dumped. If the next byte in memory following R was not a 0, you would see even more characters printed. This behavior is dependent on the [possibly atrbitarary] content of your memory.
How to handle the issue (2 ways):
1. You can either increase the size of L and R to 33, and assign the last char to \0:
char L[33]; // left part
char R[33]; // right part
/* ... */
L[32] = '\0';
R[32] = '\0';
2. Or specify to printf the length of the strings (32) like this:
/*----------vvv-------*/
printf("L: %.32s\n", L);
printf("R: %.32s\n", R);
In the later case keep in mind that L and R are not "regular" C strings, which are expected to be zero terminated (at least as far as it concerns common functions like strlen, strcmp etc.).

Related

C - repeat a string for a specific number of times in anothervariable

I want to repeat a string - for example hello - for a specific number of imes - for example 3 times -, but it doesnt work :) The example should look like this: hellohellohello, but I get no output or i get HHHHHHHHHHH...
here is my code:
char *repeat_str(size_t count, char *src) {
int length = strlen(src);
int z = length;
char *ausgabe = calloc((length*(count+1)), sizeof(char));
for(int i = 0; i<=((int) count);i++){
for(int j =0; j< length; j++){
ausgabe[i+j+z] = src[j];
}
z=z*2;
}
//printf("%s\n", ausgabe);
return(ausgabe);
}
If i remove the 'z' in the brackets of 'ausgabe', i get the output HHHHHHHH%, with the z I just get no output. Could bdy pls help me change this behavoiur - and more important, understant why it does that?
As you are always referring *src, which is fixed to the first letter of src,
the result looks like repeating it. Would you please try instead:
char *repeat_str(size_t count, char *src) {
int length = strlen(src);
char *ausgabe = calloc(length * count + 1, sizeof(char));
for (int i = 0; i < count; i++) {
for (int j = 0; j < length; j++) {
ausgabe[i * length + j] = src[j];
}
}
//printf("%s\n", ausgabe);
return ausgabe;
}
The strcat function is your friend. We can calloc a buffer long enough for n source strings, plus one for the null terminator, and then just concatenate the source string onto that buffer n times.
char *repeat_string(int n, const char *s) {
int len = strlen(s) * n + 1;
char *result = calloc(len, 1);
if (!result) return NULL;
for (int i = 0; i < n; i++) {
strcat(result, s);
}
return result;
}

In c, when I use %s to print out the contents of a char array it prints blank, but when I loop over it and print each character it works

Just implementing a simple sorting algorithm to sort a string. I tried printing out the buff char array with printf("%s\n") but it came out blank. The contents of the array are there, though, and I checked with printing out each character of it. What am I missing here?
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char const *argv[])
{
if (argc != 2)
{
printf("usage: ./sortstring string");
exit(1);
}
int size = 1; // 1 to account for '\0'
for (int i = 0; argv[1][i] != '\0'; i++)
{
size += 1;
}
char buff[size];
strcpy(buff, argv[1]);
char temp;
for (int i = 0; i < size; i++)
{
for (int j = i + 1; j < size; j++)
{
if (tolower(buff[i]) > tolower(buff[j]))
{
temp = buff[i];
buff[i] = buff[j];
buff[j] = temp;
}
}
}
// printf("%s\n", buff);
for (int i = 0; i < size; i++)
{
printf("%c", buff[i]);
}
return 0;
}
Change "%c" to "%d" in printf and see the result.
for (int i = 0; i < size; i++)
{
printf("%d", buff[i]);
}
strcpy copies terminating null byte with the source string.
You sorted terminating null byte with other characters.
Your sorting function is probably sorting the null character to position 0.
Instead of attempting to manually count characters in "argc[1]", you could just use the "strlen" function. So, instead of
int size = 1; // 1 to account for '\0'
for (int i = 0; argv[1][i] != '\0'; i++)
{
size += 1;
}
You could use
int size = strlen(argv[1]);
Regards.
The problem is that you're initializing size with 1. I know you did that because you need one more char to \0, but after that, either you need to loop through size - 1 or you can decrease the value of size before your for loops.
Another thing you can do is: initialize size with 0, and use size + 1 while creating your array.

How to store a substring given a delimiter in C

Let's say I have a series of data that's in this form:
"SomethingIDontCareAbout : SomethingICareAbout"
where the part after the ":" can vary in length of course.
The goal here is only storing the "SomethingICareAbout" substring efficiently. I made this function but the problem is that I'm storing both substrings,so it seems like a waste of memory. Any help to reduce to the time/space complexity?
char** ExtractKey(char* S)
{
int n = strlen(S);
int count = 0, i = 0, j = 0;
for(i = 0; i < n; i++)
{
if(S[i] == ':')
break;
count++;
}
char** T = (char**)malloc(2 * sizeof(char*));
T[0] = (char*)malloc((count + 1) * sizeof(char));
T[1] = (char*)malloc((n - count) * sizeof(char));
for(i = 0; i < count; i++) // inefficient ? cus we won't need T[0] [j]
{
T[0][j] = S[i];
j++;
}
T[0][j+1] = '\0';
j = 0;
for(i = count + 1; i < n; i++)
{
T[1][j] = S[i];
j++;
}
T[1][j+1] = '\0';
return T;
}
There is no reason to invent a search for a character in a string, or a copy of a string.
If the input data will live long enough for you to use the "value" part, just return a pointer to the value:
char* ExtractKey(char* S)
{
return strchr(S, ':');
}
If it doesn't, or if you for some reason need a separate copy:
char* ExtractKey(char* S)
{
return strdup(strchr(S, ':'));
}
Honestly, this could be done efficiently if strtok() was used to split those strings. I have designed the following code that parses each string of a 2-D array with a common delimiter that is : here.
Now, let's take a look into the code (notice the comments):
#include <stdio.h>
#include <string.h>
#define MAX_LEN 128
int main(void) {
// The 2-D string
char str[][MAX_LEN] = {"SomethingElse : SomethingToCareAbout",
"Something2 : SomethingToCare2",
"Unnecessary : Necessary"};
int size = sizeof(str) / sizeof(str[0]);
// Applying Variable-Length Array (valid in C)
char store_cared_ones[size][MAX_LEN];
for (int i = 0; i < size; i++) {
// Declaring a temporary pointer variable to obtain the required
// substring from each string
char *sub_str = NULL;
sub_str = strtok(str[i], ": ");
sub_str = strtok(NULL, ": ");
// Copying the 'sub_str' into each array element of 'store_cared_ones'
strcpy(store_cared_ones[i], sub_str);
}
// Displaying each of 'store_cared_ones'
for (int i = 0; i < size; i++)
fprintf(stdout, "%s\n", store_cared_ones[i]);
return 0;
}
Finally, let's see what that code does:
rohanbari#genesis:~/stack$ ./a.out
SomethingToCareAbout
SomethingToCare2
Necessary

sprintf to reverse an int and store as char

I"m trying to store int array as a str and display it but in the reverse order.
Its only while printing the str that i get junk.
What is wrong in my code?
int main() {
int a[] = { 1, 2, 3 }; // Output should be 321 (char)
int size = sizeof(a) / sizeof(int);
char str[size + 1];
int i;
for (size = size - 1; size >= 0; size--) {
sprintf(&str[size], "%d", a[size]);
//printf("%c\n", str[size]);
}
printf("%s\n", str); // I get garbage.
}
I modified your solution with several bug fixes. For starters, you can't assume that your integer array will only hold single digit values.
And that for loop as you have it:
for(size=size-1;size >= 0;size--)
Is very suspicious looking. (the index variable is the thing its based off?)
Simple solution
This is likely what you meant:
for(i = 0; i < size; i++) {
sprintf(&str[i],"%d", a[size-1-i]);
}
str[size] = '\0';
Or this:
str[size] = '\0';
for(i = size-1; i <= 0; i--) {
sprintf(&str[i],"%d", a[size-1-i]);
}
Better solution
I'm not sure what you are expecting to do if an integer within the a array is negative. So the - sign will just get inserted into str inplace.
The solution I have will first count how many chars are needed for each integer in a. Then it will allocate the str buffer with that length (+1 for null char).
Then we make use of the return value from sprintf to figure out where to concatenate onto. We could use strcat, but this is likely faster.
int main() {
int j = 0;
int a[] = { 1,2,3 }; // Output should be 321 (char)
int size = sizeof(a) / sizeof(int);
int length = 1; // +1 for final null char
// Count the size of characters needed for each integer
// Do a dummy sprintf and use its return value to figure out how many chars are needed
for (int i = 0; i < size; i++) {
char tmp[sizeof(int) * 5]; // sizeof(int)*5 is big enough to hold any integer including a negative value
length += sprintf(tmp, "%d", a[i]); // utilize the return value from sprintf and add it to the running length
}
char str[length];
str[0] = '\0'; // initially null terminate our string
// reverse print chars from a into str
for (int i = 0; i < size; i++) { // use i as index variable, not size
j += sprintf(str + j, "%d", a[size - 1 - i]);
}
printf("%s\n", str);
}
Alternative solution, closer to original posts, and clearly not trying to address the general problem (assume values are single digit):
int a[]={1,2,3}; // Output should be 321 (char)
int size = sizeof(a)/sizeof(int);
char str[size+1];
for(int i=0; i<size ; i++) {
str[size-1-i] = ‘0’ + a[i];
}
str[size] = 0;
printf("%s\n", str); // I get garbage.
}
Taking advantage of the assumed input value, converting each int to character representation at the reverse position.

Copying argv and checking it for a palindrome

I'm writing a program to check for palindromes. I recently picked up C and was wondering is there a reason why my take on it won't work? Does it have something to do with my use of directly copying argv into a char array
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc,char *argv[]){
int i;
int a;
int size;
for(a = 1; a < argc; a++){
char *reverseThis = argv[a];
char *normal = argv[a];
size = strlen(reverseThis);
for(i = 0; i < size; i++){
reverseThis[i] = normal[size - i - 1];
}
for(i = 0; i < size; i++){
reverseThis[i] = tolower(reverseThis[i]);
normal[i] = tolower(normal[i]);
}
if(strcmp(reverseThis,normal)==0){
printf("\"%s\": on palindromi\n",argv[i]);
}
else
printf("\"%s\": ei ole palindromi\n",argv[i]);
}
return 0;
}
In your code you are not copying the strings, you assigned both normal and reverseThis to same string argv[a].In reverseThis you need to copy argv[a] after allocating memory.
Just modify your code in forloop:
for(a = 1; a < argc; a++){
char *normal = argv[a];
size = strlen(normal);
char *reverseThis = (char*)malloc((size+1)*sizeof(char));
int j=0;
for(i = size-1; i >= 0; i++){
reverseThis[j++] = normal[i];
}
reverseThis[j]='\0';
.
.
You are using an incorrect approach.
For starters this loop
for(i = 0; i < size; i++){
reverseThis[i] = normal[size - i - 1];
}
copies the right half of the string in reverse order in the left half of the string totally overwriting its left part.
For example if you have a string like this "123456" then after the loop it will look like "654456"
This comparison also does not make sense
if(strcmp(reverseThis,normal)==0){
because the both pointers point to the same string. So the condition always yields true.
Take into account that these declarations
char *reverseThis = argv[a];
char *normal = argv[a];
do not copy the original string pointed to by argv[a]. The declared pointers just point to the first character of the same string.
And here is a typo
printf("\"%s\": on palindromi\n",argv[i]);
^^^
The task can be done simpler without changing the strings.
For example
size_t n = strlen( argv[a] );
size_t i = 0;
while ( i < n / 2 && tolower( ( unsigned char )argv[i] ) == tolower( ( unsigned char )argv[n -i - 1] ) ) ++i;
if ( i == n / 2 )
{
printf("\"%s\": on palindromi\n", argv[a]);
}
else
{
printf("\"%s\": ei ole palindromi\n",argv[a]);
}
If you indeed need to copy the strings then either declare variable length arrays (if the compiler supports them) or allocate arrays dynamically. For example (declaring variable length arrays):
size = strlen( argv[a] );
char reverseThis[size + 1];
char normal[size + 1];
strcpy( reverseThis, argv[a] );
strcpy( normal, argv[a] );
You don't need to reverse the string and compare to find out whether the input string is palindrome or not.
You can simply compare the characters of the string starting from both ends of the string and move one character forward from the start of the string and one character backward from the end of the string. If all character matches till you reach to mid of string then the string is palindrome otherwise not a palindrome.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc,char *argv[]){
int i, a, size;
for(a = 1; a < argc; a++){
char *ptr= argv[a];
int notpalindrom = 0;
size = strlen(ptr) - 1;
for(i = 0; i < size; ){
if (tolower(ptr[i++]) != tolower(ptr[size--])){
notpalindrom = 1;
break;
}
}
if (notpalindrom)
printf ("%s is not palindrom\n", ptr);
else
printf ("%s is palindrom\n", ptr);
}
return 0;
}
The first "if" take from argv in index "i", i == to the last change that has changed in the last "for", in your case i == 4, and the program crashed cause their isn't string in that member, to fix that you should change the "i" to 0 before the "if".

Resources