向后读一个字符串并保存它(带扭曲的字符串反转)

时间:2017-10-03 18:59:45

标签: assembly mips

我是新来的,但我会尽力遵守指南。 请注意,我刚刚开始使用MiPS和MARS,所以如果我做了一些愚蠢的事情,请告诉我如何修复它以便我可以改进。

我正在为我的长途装配课程做一个学校作业,我必须翻转一个字符串。 问题是,我不能创建一个新的字符串,而是我必须修改现有的字符串。

我想我为什么要尝试在字符串中找到第一个+ n / last-n个字符,这时我可以从字符串中的最后一个字符向后走到字符串的第一个字符。 我设法读取并向后打印字符串,但现在我卡住了,并且可以在正确的方向上使用轻推。

如果您运行此代码,那么将打印字符串“dlroW olleH”并且程序将退出,到目前为止一直很好(我希望)。 我的问题是:

如何将字符串以反向格式保存到原始标签“str”?

我开始编写一些代码,但它尚未完成,请参阅与我的问题相关的部分的“反向”标签。到目前为止,这是我的代码: 请注意,我不能使用任何库,我必须手动执行此操作。

见以下编辑

public class Startup
{
    private readonly IHostingEnvironment _currentEnvironment;
    public IConfiguration Configuration { get; private set; }

    public Startup(IConfiguration configuration, IHostingEnvironment env)
    {
        _currentEnvironment = env;
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        ......

        services.AddMvc(config =>
        {
            // Requiring authenticated users on the site globally
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            config.Filters.Add(new AuthorizeFilter(policy));

            // Validate anti-forgery token globally
            config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());

            // If it's Production, enable HTTPS
            if (_currentEnvironment.IsProduction())      // <------
            {
                config.Filters.Add(new RequireHttpsAttribute());
            }            
        });

        ......
    }
}

这是有趣的部分:

.data
str: .asciiz "Hello World"
str_msg1: .asciiz "String: "
str_msg2: .asciiz "String lenght: "
str_msg3: .asciiz "String reversed: "
str_nl: .asciiz "\n"
strLen: .space 8

.text

# Printing the original string
la $a0,str_msg1
li $v0,4
syscall
la $a0,str
li $v0,4
syscall
la $a0,str_nl
li $v0,4
syscall

#Get the lenght of the string
la $a0,str
getLen:
    lb $t0,0($a0)
    beqz $t0,printLen
    addi $t1,$t1,1
    addi $a0,$a0,1
    j getLen

#saves and prints the lenght of the string
printLen:
    sb $t1,strLen
    la $a0,str_msg2
    li $v0,4
    syscall
    lb $a0,strLen
    li $v0, 1
    syscall
    la $a0,str_nl
    li $v0,4
    syscall

感谢您抽出宝贵时间阅读我的问题。 干杯!

修改

所以我可能已经找到了答案,我认为我应该发布它,以便其他人可以阅读它,也许它可以改进。我在技术上绕过了这个任务的允许范围,但最后原始字符串被改为反转格式,所以我认为应该没问题。我是通过创建缓冲区来完成的 (strBuffer .space 255)我将字符串反向复制到此缓冲区,然后将其存储在原始字符串的地址中。它似乎工作,我欣喜若狂!

我改变的代码如下所示:

reverse:
    addi $t0,$zero,0 #zeroing the t registers to clear them for the next part.
    addi $t1,$zero,0
    addi $t2,$zero,0

    la $a1,str             #contains the adress of the string
    lb $a2,strLen          #contains the lenght of the string 
    add $a1,$a1,$a2          #adds the lenght of the string to the adress meaning it now stores the last position of the string
    add $t0,$a2,$zero    #counter initiated to lengt of the string
    loop:
        subi $a1,$a1,1  #decrement the adress since we dont want the null terminator string
        beqz $t0,exit      #if the counter variable is zero we have gone over the entire range of the strings index,then exit
        subi $t0,$t0,1  #decrement the counter since if we are here then we have not reached the end yet
                          #<temporary print statement below is for debugging purposes>
        lb $a0,0($a1)   #loads the first byte from the adress stored at $a1 which will be the string in decending order
        li $v0,11         #print character syscall
        syscall
        j loop
# Exit the program
exit:
    li $v0,10
    syscall

我已经在这里待了6个多小时了,所以请原谅我缺乏合适的风格和缩进。它似乎工作,从我可以告诉MARS数据段显示,字符串得到反转。

欢呼声

2 个答案:

答案 0 :(得分:2)

哇,谢谢你的帮助!我在晚安睡觉后检查了我的代码,男孩看起来很乱。在阅读完回复后,我重写了整篇文章并且它有效:D(见底部的代码)

我想非常感谢@ Ped7g和@PeterCordes发布了这么多评论,告诉我我可以改进什么以及在使用MiPS时我应该考虑的一些事情。谢谢,我今天学到了一些东西。

.data 
str: .asciiz "ThE qUiCk BrOwN fOx JuMpS oVeR tHe LaZy DoG"
str_msg1: .asciiz "Original string: "
str_msg2: .asciiz "Reversed string: "
str_nl: .asciiz "\n"
str_len: .word 0

.text
main:
#print original string
    la $a0,str_msg1     #leading text
    li $v0,4
    syscall
    la $a0,str              #original string
    li $v0,4
    syscall
    la $a0,str_nl           #new Line
    li $v0, 4
    syscall

#get lenght
    add $t0,$zero,$zero     #initialize registers when needed
    add $a0,$zero,$zero
    add $a1,$zero,$zero
    la $a0,str            #loads the adress of the string into two registers
    la $a1,str      
    getLen:
        lb $t0,0($a0)       #load first byte
        beqz $t0,saveLen  #check if byte is null and if so, goto saveLen
        addi $a0,$a0,1  #if not then increment the adress and keep going
        j getLen          #jump back to start of this loop
    saveLen:
        subu $t0,$a0,$a1  #len = adress of null terminator - str adress
        sw $t0,str_len

#reverse the string
    add $t0,$zero,$zero     #will hold the adress of the beginning of str
    add $t1,$zero,$zero     #will hold the adress of the end of str
    add $t2,$zero,$zero     #swap 1 
    add $t3,$zero,$zero     #swap 2 
    revString:
        #find the index of the last character before the end of the string
        la $t0,str             #loads the adress of the start of the string
        lw $t1,str_len         #loads the lenght of the string
        addu $t1,$t0,$t1      #now t1 is pointing to the null terminator
        subi $t1,$t1,1      #now t1 is pointing to the last character
        loop:
            lb $t2,0($t0)       #load the first character
            lb $t3,0($t1)       #load the last character
            ble $t1,$t0,printRev    #check to see when we reach the middle of the string
            sb $t3,0($t0)       #store the last letter at the beginning of the string
            sb $t2,0($t1)       #store the first letter at the end of the string
            addi $t0,$t0      #then increment/decrement the adress registers 
            subi $t1,$t1,1    #and loop until we reach the middle
            j loop

#print the reversed version of the text
    printRev:
    add $a0,$zero,$zero    #initialize the a0 registry
    la $a0,str_msg2      #leading text
    li $v0,4
    syscall
    la $a0,str          #reversed string
    li $v0,4
    syscall
    li $v0,10           #exit prorgram
    syscall
  

P.S。顺便说一句,我喜欢你如何设法打印掉反转的字符串而不反转它,这表明你可能已经基本掌握了正在发生的事情以及该计算机盒的工作原理 ......

谢谢你,很高兴看到:)我现在对自己感觉好一些。不过,在对这样的网站提问之后,我总会想起我还有多少不知道。

幸运的是,像你这样的人花时间传递他们的经验和建议。 Kudos man!

答案 1 :(得分:1)

反向算法建议:

Have two registers r1,r2 point to first/last character of string.
while (r1 < r2) {
    swap_chars_at_addresses(r1, r2);
    ++r1;
    --r2;
}

有关原始代码的一些评论:

strLen: .space 8

strLen保留8个字节,但在代码中将其用作byte变量,这会将代码限制为最多127个字符长的字符串(而字节可以为0)。 .255范围,lb默认情况下会对值进行符号扩展,因此要达到满255的限制,您必须将该字节视为无符号值。)

我强烈建议将其设置为:

strLen: .word 0

然后使用sw/lw将其视为32b有符号整数值,因为您可以使用该字值,并且它在指针算法中更有意义。在MARS / SPIM中也存在零风险,有人会设法为您提供超过2个 31 字符的输入字符串,并使长度值溢出为负数,因为那里有's&#39; s没有足够的内存在MARS / SPIM的虚拟MIPS机器上有这么大的字符串。虽然给你128字符长的字符串并不困难(那么你的旧代码会发疯)...

#Get the lenght of the string

它的拼写&#34;长度&#34; (我知道MARS / SPIM没有拼写检查器,但你的网络浏览器可能有)。

la $a0,str
getLen:
    lb $t0,0($a0)
    beqz $t0,printLen
    addi $t1,$t1,1
    addi $a0,$a0,1
    j getLen

你没有初始化t1,所以你很幸运MARS / SPIM在执行代码之前将寄存器归零,并且它没有在syscall内修改它们调用

但这仍然是编程的脆弱方式,而是初始化所有相关寄存器并使相关指令尽可能紧凑(彼此靠近)(即在getLen之前初始化,而不是在代码开始之前打印提示)。

此外,如果您要查看该代码,则会.. += 1;两次。这应该感觉不必要的冗余。事实上你可以避免这种情况:

la $a0,str
move $a1,$a0 # have str address also in a1
getLen:
    lb   $t0,0($a0)
    beqz $t0,getLenFinish
    addi $a0,$a0,1
    j getLen            # loop is one instruction shorter = may be faster
getLenFinish:
    subu $t0, $a0, $a1  # length = address of 0-terminator - str address
    sw   $t0,strLen     # store the calculated length into memory

现在设置那些&#34; r1,r2&#34;从我的评论中可以这么简单:

    # set t1 and t2 to point to first and last character of string
    la    $t1,str
    lw    $t2,strLen
    addu  $t2, $t1, $t2   #t2 = address of zero terminator
    subi  $t2, $t2, 1     #t2 = adr of last char (or out of bounds)
    # for empty string t2 is out of bounds now and shouldn't be dereferenced
    # And my algorithm was designed as "while (r1 < r2)" = false => no problem

这就是我要停下来的地方,因为评论很有趣......

P.S。 顺便说一句,我喜欢你如何设法打印掉反转的字符串而不反转它,这表明你可能已经基本掌握了正在发生的事情以及该计算机盒的工作原理。许多其他MIPS问题感觉作者甚至不知道&#34; string&#34;是一系列存储在内存中的字节值,实际上你可以向后读它。