Having issue with copy string values im between arrays - c

I have been working on some code that tokenizes a string from a line and then creates a temp array to copy the string into it (called copy[]) and it is filled with 0's initially (The end game is to split this copy array into temp arrays of length 4 and store them in a struct with a field char* Value). For some reason my temp arrays of size 4 end up having a size of 6.
char* string = strtok(NULL, "\"");
printf("%s", string);
int len = (int)strlen(string);
while(len%4 != 0) {
len++;
}
char copy[len];
for(int i = 0; i < len; i++){
copy[i] = '0';
}
printf("%s\n", copy);
int copyCount = 0;
int tmpCount = 0;
char temp[4];
while (copyCount < len) {
if(tmpCount == 4) {
tmpCount = 0;
}
while(tmpCount < 4) {
temp[tmpCount] = copy[copyCount];
tmpCount++;
copyCount++;
}
printf("%s %d\n", temp, (int)strlen(temp));
}
This yields:
This is the end
0000000000000000
This is the end0
This� 6
is � 6
the � 6
end0� 6
And should yield:
This is the end
0000000000000000
This is the end0
This 4
is 4
the 4
end0 4
I've been messing around with this for awhile and can't seem to figure out why its making temp have a length of 6 when I set it to 4. Also I'm not sure where the random values are coming from. Thanks!

The reason is that your string temp is not null-terminated. C-style strings should be terminated with a \0 character. For some (lucky) reason there is a \0 three bytes in memory after wherever the end of temp lives, so when strlen tries to compute its length, it gets 6. This is also why printf is printing garbage: it will print temp until it finds the null terminator, and there are garbage characters in memory before printf reaches the null terminator.

Related

How to get the length of this array without strlen(), sizeof(arr) / sizeof(arr[0]); does not work, C language

This program, tokenizes a user input string, removes extra spaces and saves each word into a 2D array and then print the tokens
EXAMPLE:
input: " Hello world string house and car"
output and EXPECTED output:
token[0]: Hello
token[1]: world
token[2]: string
token[3]: house
token[4]: and
token[5]: car
THE PROBLEM:
the problem is that I achieved this by using strlen() function when printing the tokens(code located at the very bottom), I am not supposed to use any other library than stdio.h and stdlib.h, since strlen() function is defined in string.h i tried to use sizeof(arr) / sizeof(arr[0]); but it does not work as I want, the result using sizeof is :
token[0]: Hello
token[1]: world
token[2]: string
token[3]: house
token[4]: and
token[5]: car
�oken[6]: ��
token[7]: �
token[8]: ����
token[9]: �
token[10]:
I WOULD LIKE TO HAVE THE EXPECTED OUTPUT WITHOUT USING STRLEN()
#include<stdio.h>
#include <stdlib.h>
#define TRUE 1
char tokenize(char *str, char array[10][20])
{
int n = 0, i, j = 0;
for(i = 0; TRUE; i++)//infinite loop until is the end of the string '\0'
{
if(str[i] != ' '){
//position 1, char 1
array[n][j++] = str[i];// if, it is not space, we save the character
}
else{
array[n][j++] = '\0';//end of the first word
n++;// position for next new word
j=0;// start writting char at position 0
}
if(str[i] == '\0')
break;
}
return 0;
}
//removes extra spaces
char* find_word_start(char* str){
/*also removes all extra spaces*/
char *result = (char*) malloc(sizeof(char) *1000);
int c = 0, d = 0;
// no space at beginning
while(str[c] ==' ') {
c++;
}
while(str[c] != '\0'){ // till end of sentence
result[d++] = str[c++]; //take non-space characters
if(str[c]==' ') { // take one space between words
result[d++] = str[c++];
}
while(str[c]==' ') { //
c++;
}
}
result[d-1] = '\0';
//print or return char?
return result;
free(result);
}
int main()
{
char str[]=" Hello world string dudes and dudas ";
//words, and chars in each word
char arr[10][20];
//call the method to tokenize the string
tokenize(find_word_start(str),arr);
int row = sizeof(arr) / sizeof(arr[0]);
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
for(int i = 0;i <= strlen(arr);i++)
/*----------------------------------------------------------------------*/
/*----------------------------------------------------------------------*/
printf("token[%d]: %s\n", i, arr[i]);
return 0;
}
Your code using strlen() may appear the work in this instance but it is not correct.
strlen(arr) makes no semantic sense because arr is not a string. It happens in this case to return 5 because arr has the same address as arr[0], then you kludged it to work for the 6 word output by using the test i <= strlen(arr) in the for loop. The two values strlen(arr) and the number of strings stored in arr are not related.
The expression sizeof(arr) / sizeof(arr[0]) determines the run-time constant number arrays within the array of arrays arr (i.e. 10), not the number of valid strings assigned. It is your code's responsibility to keep track of that either with a sentinel value such as an empty string, or by maintaining a count of strings assigned.
I suggest you change tokenize to return the number of strings (currently it is inexplicably defined to return a char, but in fact only ever rather uselessly returns zero):
int tokenize( char* str, char array[][20] )
{
...
return n ;
}
Then:
int rows = tokenize( find_word_start(str), arr ) ;
for( int i = 0; i < rows; i++ )
{
printf( "token[%d]: %s\n", i, arr[i] ) ;
}

C: 2-Dimensional String Array Segmentation Fault

Trying to make a small program that separates words within a big string and stores each word (of the big string) in a string (i.e pointer) in an array of strings (i.e pointers); forming a 2-dimensional string array.
The word separator is simply a whitespace (32 in ASCII); the big string is:
"Showbizzes Oxygenized Equalizing Liquidized Jaywalking"
Note:
the words are all 10 characters in length
the total length of the string is 54 characters (spaces included)
the total size of the buffer is 55 bytes ('\0' included)
One more thing, the last pointer in the array of pointers must hold a 0 (i.e 1 character: '\0') (this is completely arbitrary).
Here is the program, nothing special, but ...
#include <stdio.h>
#include <stdlib.h>
int main(void) {
// The string that we need to break down into individual words
char str[] = "Showbizzes Oxygenized Equalizing Liquidized Jaywalking";
// Allocate memory for 6 char pointers (i.e 6 strings) (5 of which will contain words)
// the last one will just hold 0 ('\0')
char **array; array = malloc(sizeof(char *) * 6);
// i: index for where we are in 'str'
// r: index for rows of array
// c: index for columns of array
int i, r, c;
// Allocate 10 + 1 bytes for each pointer in the array of pointers (i.e array of strings)
// +1 for the '\0' character
for (i = 0; i < 6; i++)
array[i] = malloc(sizeof(char)*11);
// Until we reach the end of the big string (i.e until str[i] == '\0');
for (i = 0, c = 0, r = 0; str[i]; i++) {
// Word seperator is a whitespace: ' ' (32 in ASCII)
if (str[i] == ' ') {
array[c][r] = '\0'; // cut/end the current word
r++; // go to next row (i.e pointer)
c = 0; // reset index of column/letter in word
}
// Copy character from 'str', increment index of column/letter in word
else { array[c][r] = str[i]; c++; }
}
// cut/end the last word (which is the current word)
array[c][r] = '\0';
// go to next row (i.e pointer)
r++;
// point it to 0 ('\0')
array[r] = 0;
// Print the array of strings in a grid - - - - - - - - - - - - - -
printf(" ---------------------------------------\n");
for (r = 0; r < 6; r++) {
printf("Word %i --> ", r);
for (c = 0; array[c][r]; c++)
printf("| %c ", array[c][r]);
printf("|");printf("\n");
printf(" ---------------------------------------");
printf("\n");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
return 0;
}
.. there's something wrong and I don't understand how to fix it.
For some reason it copies into the first string (i.e pointer), in the array of strings (i.e pointers), the first 6 characters of the big string, then on the 7th it gives a segmentation fault. I've allocated 6 pointers each with 11 bytes.. at least thats what I think the code is doing, so really I have NO clue why this is happening...
Hope someone can help.
Replace all ocurrences of array[c][r] with array[r][c]
The first dimension is the row.
Next time you can check this using a debugger:
Program received signal SIGSEGV, Segmentation fault.
0x00000000004007ea in main () at demo.c:37
37 array[c][r] = str[i];

Error in dynamic creation of string array

I am trying to read strings from file and insert them into matrix. Every line is one word.
FILE *fp = fopen("zadanie4.txt","r");
if( fp == NULL)
{
perror("Error while opening the file.\n");
exit(EXIT_FAILURE);
}
int symbol, num_of_lines = 0, len_of_string = 0, max_len = 0;
do {
symbol = fgetc(fp);
len_of_string++;
if (symbol == '\n' || feof(fp)) {
num_of_lines++;
if(len_of_string > max_len){
max_len = len_of_string;
}
len_of_string = 0;
}
} while (symbol != EOF);
fclose(fp);
printf("Number of words: %d\n", num_of_lines);
printf("Longest word: %d\n", max_len);
fp = fopen("zadanie4.txt","r");
char (*arr)[num_of_lines] = calloc(num_of_lines, sizeof(char*) * max_len);
int index = 0;
while(fscanf(fp, "%s", arr[index++]) == 1) {
printf("%s\n", arr[index - 1]); //first check to see what is written into array
}
close(fp);
printf("--------------------------\n");
int i;
for(i = 0; i < num_of_lines; i++){
printf("%s\n", arr[i]); //second check
}
I find out size of longest string and allocate memory for number of strings * longest string.
Here is how output looks like if longest word is 5 (+1 for empty '\0'):
Number of words: 6
Longest word: 6
AAAAA
BBBBB
CCCCC
DDDDD
EEEEE
FFFFF
--------------------------
AAAAA
BBBBB
CCCCC
DDDDD
EEEEE
FFFFF
If I add another char to every line:
Number of words: 6
Longest word: 7
AAAAAa
BBBBBb
CCCCCc
DDDDDd
EEEEEe
FFFFFf
--------------------------
AAAAAaBBBBBbCCCCCcDDDDDdEEEEEeFFFFFf
BBBBBbCCCCCcDDDDDdEEEEEeFFFFFf
CCCCCcDDDDDdEEEEEeFFFFFf
DDDDDdEEEEEeFFFFFf
EEEEEeFFFFFf
FFFFFf
Note: Every string is same size in this example, but I want it to work for various sizes.
Can anybody aid me how to properly allocate memory for this array?
Your declaration and allocation of arr are wrong and don't match.
You declare arr as a pointer to an array of num_of_lines characters. Then you allocate max_len number of pointers to character.
You can use variable-length arrays for both the outer and inner arrays:
char arr[num_of_lines][max_len + 1]; // +1 for string terminator
No need for dynamic allocation at all.
I believe you don't really understand how calloc works. You can't assign memory to the members of an array using
char (*arr)[num_of_lines] = calloc(num_of_lines, sizeof(char*) * max_len);
The first parameter of calloc will be the amount of blocks to allocate for an array and the second parameter will be the size of each block in bytes.
Instead you want to define the array like this
char *arr[num_of_lines];
Now you need to loop through each member and allocate memory for it
for(int i = 0; i < num_of_lines; i++) {
arr[i] = malloc(sizeof(char) * max_len);
}
Alternatively you can just define the array as a static array because you know the size of max_len.
You're seeing that behavior because you are over-writing the string terminator (null character == 0) at the end of each string when you add the extra character.
Instead of using one contiguous block of memory, you'll want to keep an array of string pointers, and allocate each string separately:
char *strings[];
strings = calloc(sizeof(char*),NUMBER_OF_STRINGS);
for i = 0; i < NUMBER_OF_STRINGS; i++ {
strings[i] = calloc(sizeof(char), MAX_STRING_LENGTH+1);
}
Then, when you want to add a character to a string, use strcat if the new total is less than the max string length:
strcat(strings[i],"-suffix");
Or, if it is longer, you'll need to reallocate the storage:
strings[i] = realloc(strings[i], MAX_STRING_LEN+EXTRA_BYTES+1);
strcat(strings[i],"-suffix");

printf() prints whole char matrix

As marked in the code, the first printf() rightfully prints only the i-th line of the matrix. But outiside the loop, both printf() and strcat() act on the whole matrix from i-th line on as a single-lined string. This means that
printf("%s\n",m_cfr[0])
will print whole matrix, but m_cfr[i] will print whole matrix from the i-th line on. char* string is a single lined string with no spaces.
trasp(char* string)
{
int row = strlen(string) / 5;
char m[row][5];
char m_cfr[row][5];
char cfr[row*5];
memset(cfr, 0, row * 5);
int key[5] = {3, 1, 2, 0, 4};
int k = 0;
for (i = 0 ; i < row ; i++)
{
strncpy(m[i], string + k, 5);
m[i][5] = '\0';
k += 5;
}
for (i = 0 ; i < row ; i++)
{
for (j = 0 ; j < 5 ; j++)
{
m_cfr[i][key[j]] = m[i][j];
}
m_cfr[i][5] = '\0';
printf("%s\n", m_cfr[i]); //--->prints only line i
}
printf("%s\n", m_cfr[0]); //prints whole matrix
strcat(cfr, m_cfr[0]); //concatenates whole matrix
printf("%s\n", cfr);
}
In your code, your array definition is
char m_cfr[row][5];
while you're accessing
m_cfr[i][5] = '\0';
/* ^
|
there is no 6th element
*/
You're facing off-by-one error. Out-of-bound memory access causes undefined behaviour.
Maybe you want to change the null-terminating statement to
m_cfr[i][4] = '\0'; //last one is null
%s expects a char* and prints everything until it encounters a \0. So,
printf("%s\n", m_cfr[i]);
printf("%s\n",m_cfr[0]);
strcat(cfr,m_cfr[0]);
All exhibit Undefined Behavior as m_cfr[i],m_cfr[0] and m_cfr[0] are chars and not char*s and %s as well as both the arguments of strcat expects a char*. Also, as SouravGhosh points out, using
m_cfr[i][5] = '\0';
And
m[i][5] = '\0';
Are wrong.
To fix the former issue, use
printf("%s\n", &m_cfr[i]);
printf("%s\n",m_cfr);
strcat(cfr,&m_cfr[0]);
To print the whole string and concatenate the two strings in the arguments of strcat or if you wanted to print just the chars, use
printf("%c\n", m_cfr[i]);
printf("%c\n",m_cfr[0]);
As for the latter issue, use
char m[row][5]={{0}};
char m_cfr[row][5]={{0}};

printf cause problems with output

I have a little problem with the following C code. If I comment out "LINE 24" then I'll get the following output:
aaaaaaaaaaaaaaaaaaaaaaaaa
and if I don't comment it, I'll get the following:
aaaaaaaaaaaaaaaaaaaaaaaaadƔ?LƔ?LƔF?W?F?W?F?W?F?W?F?W?F?W?F?W?
Can somebody tell me why?
I am using mac os x 10.5.4 and gcc
void test(char* a , char* b);
int main()
{
char * str = "aaaaaaaaaaaaaaaaaaaaaaaaa";
char* str2 = malloc(4*sizeof(str));
test(str , str2);
return 0;
}
void test(char* a , char* b)
{
int i = 0;
printf("\n########\n");
for( i = 0 ; i < strlen(a) ; i++)
{
printf("%d" , i); /******** LINE 24 ********/
b[i] = a[i];
}
printf("\n########\n");
for( i = 0 ; i < strlen(b) ; i++)
{
printf("%c" ,*(b+i));
}
printf("\n########\n");
}
Thank you for responding.
I see two problems in your code:
First the allocation of str2:
char* str2 = malloc(4*sizeof(str)); // This will allocate 4 times the size of a char pointer. You cannot be sure that str will fit!
Second the copying of a to b.
You need to add a string terminator at the end of b:
for( i = 0 ; i < strlen(a) ; i++)
{
printf("%d" , i); /******** LINE 24 ********/
b[i] = a[i];
}
b[i] = '\0'; // Make sure b is properly terminated
char * str = "aaaaaaaaaaaaaaaaaaaaaaaaa";
char* str2 = malloc(4*sizeof(str));
str is a pointer which size is (presumably) 32 bit -> 4 bytes. So what you are allocating is not the size of the string, but the size four pointers to a string would require (16 bytes), whilke your string is 26 bytes long (including the 0 byte).
Addirtionally, when you output a string you must allocate one byte more than the length, to account for the 0 byte which indicates the end of the string.
char * str = "aaaaaaaaaaaaaaaaaaaaaaaaa";
char* str2 = malloc(strlen(str)+1);
int i;
for( i = 0 ; i < strlen(a) ; i++)
{
printf("%d" , i); /******** LINE 24 ********/
b[i] = a[i];
}
b[i] = 0; // Terminate the string.
If you don't terminate the string, then functions working on strings (like strlen, printf etc.) will scan the string untl they encounter the 0 byte which can be anywhere in your memory. So the strlen in your code, can sometimes seem to give the correct length if such a byte happens to be right at the end, but it will give wrong results more often (undefined behaviour), which accounts for the strange chars you see at your output.

Resources