This question already has answers here:
Variable Sized Arrays in C
(5 answers)
Closed 7 years ago.
I have to take a phrase from the user, and print it out in an inverted triangle with spaces in between. My program takes the phrase, stores it into an inputBuffer (array of char), and then creates a new array double the size of string. It fills up the first half with spaces, and the second half with the string itself. I want to print out the strLength char from the new array strLength times, just by shifting the range of strLength to (strLength*2-1) by 1 each time to the left. This ensures that in the first iteation, only the whole string is printed, second time one space at the beginning and one char at the end is not printed, as so on. Currently I am getting an error that even through strLength is an int variable, when I use it to create the new array it's apparently NOT a constant value.
int main(void) {
char inputBuffer[256];
char *pointer = inputBuffer;
char *temp = pointer;
int strLength = 0;
printf("enter your word: ");
scanf("%s", pointer);
//Calculate string length
while (*temp++) strLength++;
//Create an array double the size, first half for white spaces, and second half for the phrase.
char inputString[strLength * 2];
// ERROR: above expression inside the index must be a constant value.
int i, j;
//First half of array is number of spaces == number of char in phrase
for (i = 0; i < strLength; i++) {
inputString[i] = ' ';
}
//Reinitialize temp to use instead of pointer & put the string in the second half of inputString[]
temp = pointer;
for (j = 0; j < strLength; j++) {
inputString[i++] = *temp++;
}
//Just print the strLength indexes of inputStrng[] starting from half to end, and keep shifting the range by 1 position to the left.
for (i = strLength; i < (strLength * 2); i--) {
for (j = 0; j < strLength; j++) {
putchar(inputString[i + j]);
putchar(' ');
}
putchar('\n');
}
return 0;
}
The index variable your using to create inputString is infact not a constant, it's a variable..
If you want to create an array of a variable size, you have to use malloc.. You have to replace the line char inputString[strLength * 2]; with a malloc statement..
See this answer
So.. something like this:
char * inputString = malloc( sizeof(char) * ( (strLength * 2) + 1 ) );
Related
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] ) ;
}
I'm trying to create an array of patterns for a triangle that I'm also printing to the console. I do this by creating a 2d char array where
char patterns [number_of_patterns][pattern_lengths]. I pass this to a function that takes the array patterns along with the height of the triangle I'm trying to make.
void printTriangle (int rows, char rowPatterns[][rows]) {
int initialSpaces = rows - 1;
int numberOfAsterisks = 1;
int i;
for (i = 0; i < rows; i++) {
char temp[rows];
int spaceCounter = 0;
int asteriskCounter = 0;
while (spaceCounter < initialSpaces) {
printf(" ");
sprintf(temp, " ");
spaceCounter++;
}
while (asteriskCounter < numberOfAsterisks) {
sprintf(temp, "*");
printf("*");
asteriskCounter++;
}
while (spaceCounter < initialSpaces) {
spaceCounter = 0;
sprintf(temp, " ");
spaceCounter++;
}
strcpy(rowPatterns[i], temp);
printf("\n");
initialSpaces--;
numberOfAsterisks+=2;
}
}
For every row of the triangle that I'm printing, I create a string for that row called temp. At the end of the for loop that prints the row to the console and sprintf's it to the array temp, I strcpy temp into patterns[i]. Then I go back to the top of the loop, reinitialize temp to make it fresh, and loop again until I have all my rows. Except for some reason sprint won't fill in my array temp. Is this incorrect use of the function, or does it have to do w my parameter passing?
sprintf always writes to the start of the string. To append, you can maintain a pointer to the end of the string:
char *ptr = rowpatterns[i];
ptr += sprintf(ptr, "*");
You might also hear the suggestion to use strcat - avoid that function. When building strings, repeated strcat is very slow and is a common source of performance issues in string code.
I am writing a program which will take every 3 numbers in a file and convert them to their ASCII symbol. So I thought I could read the numbers into a character array, and then make every 3 elements 1 element in a second array, convert them to int and then print these as char.
I am stuck on taking every 3 elements, however. This is my code snippet for this part:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[16] = {0};
for(int i = 0; i <= sizeof(arryNew); i++){
strncpy(arryNew, arry, 3);
arryNew[i+3]='\0';
puts(arryNew);
}
What this code gives me is the first 3 numbers, fifteen times. I've tried incrementing i by 3, which gives me the first 3 numbers 5 times. How do I write a for-loop with strncpy so that after copying n chars, it moves to the next n chars?
You pass always the pointer to the beginning of the array, so you will always have the same result of course. You must include the loop counter to get at the next block:
strncpy(arryNew, &arry[i*3], 3);
Here you have a problem:
arryNew[i+3]='\0';
First of all, you don't need to set the null byte every time, because this will not change anyway. Additionally you will corrupt memory, because you use i+3 as the index so when you reach 14 and 15, it will write beyond the arrayboundary.
Your arrayNew must be longer, because your original array is 16 characters, and your target array is also. If you intend to have several 3char strings in there, then you must have 5*4 characters for your target, because each string also has the 0-byte.
And of course, you must also use the index here as well. The way it is written now, it will write beyond the array boundary, when i reaches 14 and 15.
So what you seem to want to do (not sure from your description) is:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[20] = {0};
for(int i = 0; i <= sizeof(arry); i++)
{
strncpy(&arryNew[i*4], &arry[i*3], 3);
puts(&arryNew[i*4]);
}
Or if you just want to have the individual strings printed then you can just do:
char arry[] = "073102109109112"; <--example string read from a file
char arryNew[4] = {0};
for(int i = 0; i <= sizeof(arry); i++)
{
strncpy(arryNew, &arry[i*3], 3);
puts(arryNew);
}
Making things a bit simpler: your target string doesn't change.
char arry[] = "073102109109112"; <--example string read from a file
char target[4] = {0};
for(int i = 0; i < strlen(arry) - 3; i+=3)
{
strncpy(target, arry + i, 3);
puts(target);
}
Decoding:
start at the beginning of arry
copy 3 characters to target
(note the fourth element of target is \0)
print out the contents of target
increment i by 3
repeat until you fall off the end of the string.
Some problems.
// Need to change a 3 chars, as text, into an integer.
arryNew[i] = (char) strtol(buf, &endptr, 10);
// char arryNew[16] = {0};
// Overly large.
arryNew[6]
// for(int i = 0; i <= sizeof(arryNew); i++){
// Indexing too far. Should be `i <= (sizeof(arryNew) - 2)` or ...
for (i=0; i<arryNewLen; i++) {
// strncpy(arryNew, arry, 3);
// strncpy() can be used, but we know the length of source and destination,
// simpler to use memcpy()
// strncpy(buf, a, sizeof buf - 1);
memcpy(buf, arry, N);
// arryNew[i+3]='\0';
// Toward the loop's end, code is writing outside arryNew.
// Lets append the `\0` after the for() loop.
// int i
size_t i; // Better to use size_t (or ssize_t) for array index.
Suggestion:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char Source[] = "073102109109112"; // example string read from a file
const int TIW = 3; // textual integer width
// Avoid sprinkling bare constants about code. Define in 1 place instead.
const char *arry = Source;
size_t arryLen = strlen(arry);
if (arryLen%TIW != 0) return -1; // is it a strange sized arry?
size_t arryNewLen = arryLen/TIW;
char arryNew[arryNewLen + 1];
size_t i;
for (i=0; i<arryNewLen; i++) {
char buf[TIW + 1];
// strncpy(buf, a, sizeof buf - 1);
memcpy(buf, arry, TIW);
buf[TIW] = '\0';
char *endptr; // Useful should OP want to do error checking
// TBD: test if result is 0 to 255
arryNew[i] = (char) strtol(buf, &endptr, 10);
arry += TIW;
}
arryNew[i] = '\0';
puts(arryNew); // prints Ifmmp
return 0;
}
You could use this code to complete your task i.e. to convert the given char array in form of ascii value.
char arry[] = "073102109109112";
char arryNew[16] = {0};
int i,j=0;
for(i = 0; i <= sizeof(arryNew)-2; i+=3)
{
arryNew[j]=arry[i]*100+arry[i+1]*10+arry[i+2]*1;
j++;
arryNew[j+1]='\0';
puts(arryNew);
}
Given a run length encoded string, say "A3B1C2D1E1", decode the string in-place.
The answer for the encoded string is "AAABCCDE". Assume that the encoded array is large enough to accommodate the decoded string, i.e. you may assume that the array size = MAX[length(encodedstirng),length(decodedstring)].
This does not seem trivial, since merely decoding A3 as 'AAA' will lead to over-writing 'B' of the original string.
Also, one cannot assume that the decoded string is always larger than the encoded string.
Eg: Encoded string - 'A1B1', Decoded string is 'AB'. Any thoughts?
And it will always be a letter-digit pair, i.e. you will not be asked to converted 0515 to 0000055555
If we don't already know, we should scan through first, adding up the digits, in order to calculate the length of the decoded string.
It will always be a letter-digit pair, hence you can delete the 1s from the string without any confusion.
A3B1C2D1E1
becomes
A3BC2DE
Here is some code, in C++, to remove the 1s from the string (O(n) complexity).
// remove 1s
int i = 0; // read from here
int j = 0; // write to here
while(i < str.length) {
assert(j <= i); // optional check
if(str[i] != '1') {
str[j] = str[i];
++ j;
}
++ i;
}
str.resize(j); // to discard the extra space now that we've got our shorter string
Now, this string is guaranteed to be shorter than, or the same length as, the final decoded string. We can't make that claim about the original string, but we can make it about this modified string.
(An optional, trivial, step now is to replace every 2 with the previous letter. A3BCCDE, but we don't need to do that).
Now we can start working from the end. We have already calculated the length of the decoded string, and hence we know exactly where the final character will be. We can simply copy the characters from the end of our short string to their final location.
During this copy process from right-to-left, if we come across a digit, we must make multiple copies of the letter that is just to the left of the digit. You might be worried that this might risk overwriting too much data. But we proved earlier that our encoded string, or any substring thereof, will never be longer than its corresponding decoded string; this means that there will always be enough space.
The following solution is O(n) and in-place. The algorithm should not access memory it shouldn't, both read and write. I did some debugging, and it appears correct to the sample tests I fed it.
High level overview:
Determine the encoded length.
Determine the decoded length by reading all the numbers and summing them up.
End of buffer is MAX(decoded length, encoded length).
Decode the string by starting from the end of the string. Write from the end of the buffer.
Since the decoded length might be greater than the encoded length, the decoded string might not start at the start of the buffer. If needed, correct for this by shifting the string over to the start.
int isDigit (char c) {
return '0' <= c && c <= '9';
}
unsigned int toDigit (char c) {
return c - '0';
}
unsigned int intLen (char * str) {
unsigned int n = 0;
while (isDigit(*str++)) {
++n;
}
return n;
}
unsigned int forwardParseInt (char ** pStr) {
unsigned int n = 0;
char * pChar = *pStr;
while (isDigit(*pChar)) {
n = 10 * n + toDigit(*pChar);
++pChar;
}
*pStr = pChar;
return n;
}
unsigned int backwardParseInt (char ** pStr, char * beginStr) {
unsigned int len, n;
char * pChar = *pStr;
while (pChar != beginStr && isDigit(*pChar)) {
--pChar;
}
++pChar;
len = intLen(pChar);
n = forwardParseInt(&pChar);
*pStr = pChar - 1 - len;
return n;
}
unsigned int encodedSize (char * encoded) {
int encodedLen = 0;
while (*encoded++ != '\0') {
++encodedLen;
}
return encodedLen;
}
unsigned int decodedSize (char * encoded) {
int decodedLen = 0;
while (*encoded++ != '\0') {
decodedLen += forwardParseInt(&encoded);
}
return decodedLen;
}
void shift (char * str, int n) {
do {
str[n] = *str;
} while (*str++ != '\0');
}
unsigned int max (unsigned int x, unsigned int y) {
return x > y ? x : y;
}
void decode (char * encodedBegin) {
int shiftAmount;
unsigned int eSize = encodedSize(encodedBegin);
unsigned int dSize = decodedSize(encodedBegin);
int writeOverflowed = 0;
char * read = encodedBegin + eSize - 1;
char * write = encodedBegin + max(eSize, dSize);
*write-- = '\0';
while (read != encodedBegin) {
unsigned int i;
unsigned int n = backwardParseInt(&read, encodedBegin);
char c = *read;
for (i = 0; i < n; ++i) {
*write = c;
if (write != encodedBegin) {
write--;
}
else {
writeOverflowed = 1;
}
}
if (read != encodedBegin) {
read--;
}
}
if (!writeOverflowed) {
write++;
}
shiftAmount = encodedBegin - write;
if (write != encodedBegin) {
shift(write, shiftAmount);
}
return;
}
int main (int argc, char ** argv) {
//char buff[256] = { "!!!A33B1C2D1E1\0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" };
char buff[256] = { "!!!A2B12C1\0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" };
//char buff[256] = { "!!!A1B1C1\0!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" };
char * str = buff + 3;
//char buff[256] = { "A1B1" };
//char * str = buff;
decode(str);
return 0;
}
This is a very vague question, though it's not particularly difficult if you think about it. As you say, decoding A3 as AAA and just writing it in place will overwrite the chars B and 1, so why not just move those farther along the array first?
For instance, once you've read A3, you know that you need to make space for one extra character, if it was A4 you'd need two, and so on. To achieve this you'd find the end of the string in the array (do this upfront and store it's index).
Then loop though, moving the characters to their new slots:
To start: A|3|B|1|C|2|||||||
Have a variable called end storing the index 5, i.e. the last, non-blank, entry.
You'd read in the first pair, using a variable called cursor to store your current position - so after reading in the A and the 3 it would be set to 1 (the slot with the 3).
Pseudocode for the move:
var n = array[cursor] - 2; // n = 1, the 3 from A3, and then minus 2 to allow for the pair.
for(i = end; i > cursor; i++)
{
array[i + n] = array[i];
}
This would leave you with:
A|3|A|3|B|1|C|2|||||
Now the A is there once already, so now you want to write n + 1 A's starting at the index stored in cursor:
for(i = cursor; i < cursor + n + 1; i++)
{
array[i] = array[cursor - 1];
}
// increment the cursor afterwards!
cursor += n + 1;
Giving:
A|A|A|A|B|1|C|2|||||
Then you're pointing at the start of the next pair of values, ready to go again. I realise there are some holes in this answer, though that is intentional as it's an interview question! For instance, in the edge cases you specified A1B1, you'll need a different loop to move subsequent characters backwards rather than forwards.
Another O(n^2) solution follows.
Given that there is no limit on the complexity of the answer, this simple solution seems to work perfectly.
while ( there is an expandable element ):
expand that element
adjust (shift) all of the elements on the right side of the expanded element
Where:
Free space size is the number of empty elements left in the array.
An expandable element is an element that:
expanded size - encoded size <= free space size
The point is that in the process of reaching from the run-length code to the expanded string, at each step, there is at least
one element that can be expanded (easy to prove).
Trying to use as basic C as I can to build a list of numbers from 1-52 in a random order (deck of cards). Everything works, but all of my attempts to concat the strings and get a result end in failure. Any suggestions? NOTE: This is not homework it's something I'm using to create a game.
// Locals
char result[200] = ""; // Result
int card[52]; // Array of cards
srand(time(0)); // Initialize seed "randomly"
// Build
for (int i=0; i<52; i++) {
card[i] = i; // fill the array in order
}
// Shuffle cards
for (int i=0; i<(52-1); i++) {
int r = i + (rand() % (52-i));
int temp = card[i]; card[i] = card[r]; card[r] = temp;
}
// Build result
for (int c=0; c<52; c++) {
// Build
sprintf(result, "%s%d", result, card[c]);
// Comma?
if ( c < 51 )
{
sprintf(result, "%s%s", result, ",");
}
}
My end result is always garbled text. Thanks for the help.
You keep writing to the same position of "result".
sprintf is not going to do the appending for you.
You may consider, after each sprintf, get the return value (which is the number of char written), and increment the pointer to result buffer. i.e. something like:
(psuedo code):
char result[200];
char * outputPtr = result;
for (int c=0; c<52; c++) {
// Build
int n = sprintf(outputPtr, "%d%s", card[c], (c<51 ? "," : ""));
outputPtr += n;
}
Are we writing C++ or C? In C++, concat-ing a string is just:
string_out = string_a + string_b
…since you'd be using std::string.
Furthermore, if this is C++, the STL has a std::shuffle function.
If this is C, note that all your sprintfs aren't concatenating strings, they're just overwriting the old value.
I think, if memory serves, that sprintf will always write into the buffer starting at byte 0. This means that you would be writing the first couple of bytes over and over again with a number, then a comma, then a number. Check if your first bytes are ",[0-9]" - if so, that's your issue.
This would add a comma between each number in the result string:
// Get a pointer to the result string
char* ptr = &result[0];
for (int c = 0; c < 52; c++) {
// Add each cards number and increment the pointer to next position
ptr += sprintf(ptr, "%d", card[c]);
// Add a separator between each number
if (c < 51) {
*ptr++ = ',';
}
}
// Make sure the result string is null-terminated
*ptr = 0;